3

所以问题来了,我们有一个用户想要显示的数据。查询,我们优化和索引的速度与我认为的一样快。我们可能会减少一两秒钟,但由于数据量很大,我们无能为力。

无论如何,因此查询在仅限于一两天的数据时运行得很好,但是用户正在运行它一两个星期的数据。所以查询两三周的数据大约需要 40 秒,Heroku 超时为 30 秒,这是行不通的。所以我们需要一个解决方案。

所以在这里和谷歌搜索,我看到 webhooks 或 Ajax 可以作为解决方案的评论。但是,我一直无法找到一个真实的具体例子。我还看到一条评论,有人说我们可以发送某种“重置时钟”的回复。但再次听起来很有趣,但找不到一个例子。

我们有点不知所措,用户不满意,所以我们需要一个快速简单的解决方案。在此先感谢您的帮助!

4

1 回答 1

1

我遇到了类似的问题。我在我的 Sinatra 应用程序中有一个本质上是“批量下载”页面,我的客户端应用程序调用它来将数据导入浏览器中的本地 webSQL 数据库。

下载页面(我们称之为“GET /download”)查询 CouchDB 数据库以获取给定视图中的所有文档,而这部分过程(很像您的查询)需要很长时间。

通过使用 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

这对我来说效果很好,因为“第一个字节的时间”(即 db 查询返回第一行所用的时间远低于 30 秒的限制。

唯一的缺点是之前我将所有结果从数据库中返回到我的 Sinatra 应用程序中,然后计算整个结果的 MD5 和以用作 etag 标头。我的客户端应用程序可以使用它来执行条件 HTTP 获取(即,如果它尝试再次下载并且没有修改任何数据,我可以发送 302 Not Modified);另外,它可以与它自己收到的数据的校验和进行比较(以确保它在传输过程中没有被损坏/修改)。

一旦您开始在响应中流式传输数据,您将无法计算要作为 HTTP 标头发送的内容的 MD5 总和(因为您还没有所有数据;并且您无法在之后发送标头)已经开始发送正文内容)。

我正在考虑将其更改为某种分页、多 AJAX 调用的解决方案;正如 Zenph 上面建议的那样。或者使用某种工作进程(例如 Resque、DelayedJob)将查询卸载到;但是我不确定当数据准备好获取时如何通知客户端。

希望这可以帮助。

于 2013-03-11T13:21:06.693 回答