我想在 Rails 应用程序中添加类似“背景”线程的东西。我需要不时查看邮件(比如说每 10 分钟),然后根据邮件做一些事情。这应该与错误跟踪器的工作方式相同,您可以回复从错误跟踪器收到的电子邮件,它会接收电子邮件并将其添加到工单中。
有没有简单的方法在后台运行这样的东西?我不想使用 cron 或任何系统工具,只是纯粹的 ruby。我开始申请,我不应该关心其他任何事情。
我想在 Rails 应用程序中添加类似“背景”线程的东西。我需要不时查看邮件(比如说每 10 分钟),然后根据邮件做一些事情。这应该与错误跟踪器的工作方式相同,您可以回复从错误跟踪器收到的电子邮件,它会接收电子邮件并将其添加到工单中。
有没有简单的方法在后台运行这样的东西?我不想使用 cron 或任何系统工具,只是纯粹的 ruby。我开始申请,我不应该关心其他任何事情。
EventMachine 有PeriodicTimer
n = 0
timer = EventMachine::PeriodicTimer.new(5) do
puts "the time is #{Time.now}"
timer.cancel if (n+=1) > 5
end
rufus-scheduler是一个使用纯 Ruby 基础 EventMachine 编写的类似 cron 的工具。
接受的答案有几个潜在的问题值得指出。
首先,PeriodicTimer
使用尾递归重新调度自身执行,即EventMachine.add_timer
在执行其块后调用。不幸的是,代码没有使用begin-ensure-end
这意味着如果您的代码中有异常,计时器将停止。参见GH#454。
其次,存在EventMachine
作为单例在单线程中运行的反应器循环的问题。如果您PeriodicTimer
在其块中启动并执行慢速电子邮件操作,您将阻塞其他代码可能依赖的反应器循环。更好的方法是使用EventMachine::Deferrable
. 有关示例,请参见这篇文章。
最后但并非最不重要EventMachine
的一点是,如果反应器的反应器尚未运行,则应在单独的线程上运行,但如果反应器的线程已在运行,则应在反应器的线程上“安排”您的工作。
把这些放在一起,你就有了一些类似的东西:
def check_email
timer = EM::PeriodicTimer.new(10.minutes) do
begin
DefferableEmailChecker.new.errback do |error|
# handle error
# note that this code will run OUTSIDE the
# periodic timer block
end
rescue Exception => e
# even with a Deferable this is good practice
# if you want to cancel, use timer.cancel
end
end
end
if EM.reactor_running?
EM.schedule do
check_email
end
else
Thread.new do
EM.run do
check_email
end
end
end
查看Daemon-Kit。它允许您在与 Rails 项目具有相似约定的框架中创建 Ruby 守护程序。我们用它来监控和执行各种后台任务。
我在我的项目中使用了delayed_job 。
Delayed_job(或 DJ)封装了在后台异步执行较长任务的常见模式。