问题来了,我们有一个用户想要显示的数据。查询,我们优化和索引到我认为的一样快。我们可能会减少一两秒,但考虑到数据量,我们无能为力。
无论如何,当限制为一两天的数据时,查询运行得很好,但是用户正在运行一两周的数据。所以查询两三周的数据大约需要 40 秒,Heroku 超时 30 秒,这是行不通的。所以我们需要一个解决方案。
所以在这里和谷歌搜索,我看到评论说 webhooks 或 Ajax 可以作为解决方案。但是,我一直无法找到一个真实的具体示例。我还看到一条评论,有人说我们可以发送某种“重置时钟”的回复。但再次听起来很有趣,但找不到例子。
我们有点受到攻击,用户不满意,所以我们需要一个快速简单的解决方案。在此先感谢您的帮助!
最佳答案
我遇到了类似的问题。我的 Sinatra 应用程序中有一个本质上是“批量下载”页面的内容,我的客户端应用程序调用该页面将数据导入浏览器中的本地 webSQL 数据库。
下载页面(我们称之为“GET/download”)查询 CouchDB 数据库以获取给定 View 中的所有文档,而这部分过程(很像您的查询)需要很长时间。
我能够通过使用 Sinatra 的流式 API 来解决这个问题。如上所述,您可以通过在 30 秒时间结束之前在响应中发送至少一个 by 来“重置”Heroku 中的时钟。这会将时钟重置另外 55 秒(并且您发送的每个额外字节都会再次重置时钟),因此当您仍在发送数据时,连接可以无限期地保持打开状态。
在 Sinatra 中,我能够替换它:
get '/download' do
body = db.view 'data/all'
end
..用这样的东西:
get '/download' do
# stream is a Sinatra helper that effectively does 'chunked transfer encoding'
stream do |out|
# Long query starts here
db.view 'data/all' do |row|
# As each row comes back from the db, stream it to the front-end
out << row
end
end
end
这对我来说效果很好,因为“第一个字节的时间”(即数据库查询返回第一行所花费的时间远低于 30 秒的限制。
唯一的缺点是,之前我从数据库中将所有结果返回到我的 Sinatra 应用程序中,然后计算整个结果的 MD5 总和以用作 etag header 。我的客户端应用程序可以使用它来执行有条件的 HTTP 获取(即,如果它尝试再次下载并且没有修改数据,我可以发送 302 Not Modified);此外,它还可以与它自己接收到的数据的校验和进行比较(以确保它在传输过程中没有被损坏/修改)。
一旦您开始在响应中流式传输数据,您将无法计算要作为 HTTP header 发送的内容的 MD5 总和(因为您还没有所有数据;并且您无法发送 header 在您开始发送正文内容之后)。
我正在考虑将其更改为某种分页的、多个 AJAX 调用的解决方案;正如 Zenph 上面所建议的那样。那,或者使用某种工作进程(例如Resque,DelayedJob)将查询卸载到;但是我不确定在准备好获取数据时如何通知客户端。
希望这对您有所帮助。
关于ruby-on-rails - RnR : Long running query, Heroku 超时 : webhooks? Ajax?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13272004/