如何在用户访问网页时开始重复进行后台作业?

时间:2015-10-03 23:59:27

标签: ruby-on-rails ruby resque resque-scheduler

我正在创建一个带有后台工作程序的Rails Web应用程序,用于在设置的时间间隔内在后台执行某些任务。我正在使用Resque with Redis对后台作业进行排队,并使用Resque-scheduler在设置的时间间隔内运行它,例如每隔30秒左右。

后台作业只有在用户访问特定页面时才需要加入队列,并且应该按计划运行,直到用户离开该页面为止。基本上,我想在运行时动态设置计划。我的应用程序部署在云中,主要的Rails应用程序和后台工作程序作为通过Redis进行通信的单独进程运行。如何动态设置计划,从哪里开始?

resque_schedule.yml

do_my_job:
  every: 1m
  class: BackgroundJob
  description: Runs the perform method in MyJob
  queue: backgroundq
控制器内的

  def index
    Resque.enqueue(BackgroundJob)
  end

background_job.rb

class BackgroundJob
  @queue = :backgroundq

  @job_helper = BackgroundHelper.new

  def self.perform
    @job_helper.get_job_data
  end

end

1 个答案:

答案 0 :(得分:1)

Resque-scheduler可以使用dynamic schedules完成您所描述的内容。每次用户访问您的页面时,您都会创建一个Resque.set_schedule的计划,该计划每30秒就会对该用户运行一次。当用户离开时,您将使用Resque.remove_schedule中止。我可以想象用户在没有你注意的情况下离开页面的很多方式(最坏的情况是,如果他们的计算机断电会怎么样?),所以我担心会留下时间表。我还不确定在添加越来越多的日程安排时,resque-scheduler会有多快乐,因此您可能会遇到很多用户的麻烦。

您可以通过让每个目前运行的每个用户每30秒运行一个作业来最小化计划数量,例如:

class BackgroundJob
  def self.perform
    User.active.each { ... }
  end
end

如果您在用户访问您的网页时执行了设置User#last_seen_at之类的操作并且User.active加载了过去10分钟内看到的所有人,那么您每隔30秒就会运行一次活跃的用户,并且用户离开后没有机会持续工作,因为它在10分钟内就会超时。但是,如果您的用户数超过30秒内可以工作的用户,则计划的作业将在下一个副本启动之前完成,并且会出现问题。您可以通过让顶级作业为每个用户排队实际完成工作的辅助作业来解决这个问题。然后,只要你能在30秒内做到这一点,并为你的工作量有足够的resque工人,事情应该没问题。

接近它的第三种方法是让用户的工作将其自身的另一个副本排入队列,如下所示:

class BackgroundJob
  def self.perform(user_id)
    do_work(user_id)
    Resque.enqueue_in(30.seconds, BackgroundJob, user_id)
  end
end

当用户访问您的网页时,您将第一个作业排入队列,然后它会继续运行。这种方式很好,因为每个用户的工作都是独立运行的,并且您不需要为每个用户分别设置单独的计划或管理所有内容的顶级计划。一旦用户离开,您仍然需要一种方法来停止作业,可能是超时或TTL计数器。

最后,我会质疑Resque是否适合您的任务。如果您希望每30秒发生一次,只要用户在页面上,可能您希望用户看到它发生,因此您应该考虑在浏览器中实现它。例如,您可以设置30秒的JavaScript间隔来命中执行某些工作并返回值的API端点。这样就完全不需要Resque,会在用户离开时自动停止,即使它们断电并且你的代码没有机会清理。