在Rails中处理大量数据时,用户等待的最佳实践是什么?

5
我有一个书签工具,使用后会将当前浏览器页面上的所有URL提交到Rails 3应用程序进行处理。在幕后,我使用Typhoeus检查每个URL是否返回2XX状态码。目前,我通过向Rails服务器发起AJAX请求来启动此过程,然后等待它完成并返回结果。对于少量的URL,这很快,但是当URL数量非常大时,用户可能需要等待10-15秒钟。
我考虑使用Delayed Job在用户线程之外处理此问题,但似乎不是最合适的用例。因为用户需要等待处理完成才能看到结果,而Delayed Job可能需要五秒钟才能开始作业,我无法保证处理将尽快发生。不幸的是,在这种情况下,这种等待时间是不可接受的。
理想情况下,我认为应该发生以下情况:
  • 用户点击书签
  • 将数据发送到服务器进行处理
  • 即时返回等待页面,同时启动一个线程进行处理
  • 等待页面通过ajax定期轮询处理结果并更新等待页面(例如:“已处理567个URL中的4个...”)
  • 一旦结果准备好,等待页面将被更新

一些额外的细节:

  • 我正在使用Heroku(长时间运行的进程在30秒后会被终止)
  • 已登录和匿名用户均可使用此功能

这是一种典型的做法吗?还是有更好的方法?我应该自己编写离线处理代码并在处理过程中更新数据库,还是有类似Delayed Job的东西可以用于此(并且可以在Heroku上工作)?任何有关正确方向的推荐将不胜感激。


你最终做了什么? - Ari
@Ari,自从我上次处理这个问题以来已经很长时间了,但总的来说,我使用了一个后台处理器(今天我会使用sidekiq),以及一个跟踪进度的状态机。然后,在前端使用xhr轮询,直到状态为“完成”或者你需要的任何状态。 - markquezada
谢谢。所以我猜Thread.new不能单独工作? - Ari
1个回答

1

我认为你后面的想法最有意义。我会将每个url检查的处理分配到自己的线程中(因此所有url检查都并发运行--这应该比顺序检查快得多)。每次完成时,它都会更新数据库(确保线程不会互相干扰写入)。一个AJAX端点--就像你说的那样,在客户端定期轮询--将从数据库中获取并返回已完成进程的计数。这是一个足够简单的方法,我真的看不出需要任何额外的组件。


幸运的是,Typhoeus可以并行处理URL,因此比串行处理快得多。它还提供了一个on_complete回调函数供我使用。(目前,我正在使用它将结果缓存到memcache中。)我想我无法理解的是:如何将这些数据附加到用户身上?特别是如果用户是匿名的。会话ID?如果是匿名用户,我不太希望在我的数据库中存储这些数据。 - markquezada
看起来您已经有了系统。只需向在 Typhoeus on_complete 处理程序中设置的键添加会话 ID 即可。然后在轮询端点中,根据会话 ID 访问这些 memcache 键,可以(一旦所有内容都处理完毕并返回给用户)从数据库中清除相关键。但根据您的评论,我确信您已经考虑过这个问题并有一些问题——但我并没有真正明白这个问题是什么。 - Ben Lee
啊,我想我只是没有想到直接使用memcache作为完成结果数据的临时存储。目前我只是在使用它来缓存单个URL爬行的结果。(不与特定用户绑定。)但你说得对,我完全可以使用memcache暂时存储特定用户请求的完整结果。这样,它就不会因为不是关键数据而使匿名用户的数据库变得混乱。(对于注册用户,它将被持久保存。)好主意。谢谢你帮我思考这个问题。 - markquezada

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接