12

我们必须使用delayed_job(或其他一些后台作业处理器)在后台运行作业,但我们不允许更改服务器上的启动脚本/启动级别。这意味着如果提供程序重新启动服务器,则不能保证守护程序保持可用(因为守护程序将由每个部署仅运行一次的 capistrano 配方启动)。

目前,我能想到的确保delayed_job 守护程序始终运行的最佳方法是向我们的Rails 应用程序添加一个初始化程序,以检查守护程序是否正在运行。如果它没有运行,则初始化程序启动守护程序,否则,它就让它保持原样。

因此,问题是我们如何检测 Delayed_Job 守护进程正在从脚本内部运行?(我们应该能够相当容易地启动一个守护进程,有点我不知道如何检测一个是否已经处于活动状态)。

有人有想法么?

问候,伯尼

根据下面的答案,这就是我想出的。只需将其放入 config/initializers 中即可:

#config/initializers/delayed_job.rb

DELAYED_JOB_PID_PATH = "#{Rails.root}/tmp/pids/delayed_job.pid"

def start_delayed_job
  Thread.new do 
    `ruby script/delayed_job start`
  end
end

def process_is_dead?
  begin
    pid = File.read(DELAYED_JOB_PID_PATH).strip
    Process.kill(0, pid.to_i)
    false
  rescue
    true
  end
end

if !File.exist?(DELAYED_JOB_PID_PATH) && process_is_dead?
  start_delayed_job
end
4

4 回答 4

9

更多清理思路:不需要“开始”。您应该挽救“没有这样的进程”,以免在其他问题出现时触发新进程。拯救“没有这样的文件或目录”以简化条件。

DELAYED_JOB_PID_PATH = "#{Rails.root}/tmp/pids/delayed_job.pid"

def start_delayed_job
  Thread.new do 
    `ruby script/delayed_job start`
  end
end

def daemon_is_running?
  pid = File.read(DELAYED_JOB_PID_PATH).strip
  Process.kill(0, pid.to_i)
  true
rescue Errno::ENOENT, Errno::ESRCH   # file or process not found
  false
end

start_delayed_job unless daemon_is_running?

请记住,如果您启动多个工人,则此代码将不起作用。并查看 script/delayed_job 的“-m”参数,它会与守护进程一起生成监控进程。

于 2010-12-14T17:20:31.817 回答
5

检查守护进程 PID 文件 ( File.exist? ...) 是否存在。如果它在那里,则假设它正在运行,否则启动它。

于 2010-04-05T20:57:12.927 回答
0

感谢您在问题中提供的解决方案(以及激发它的答案:-)),它对我有用,即使有多个工人(Rails 3.2.9,Ruby 1.9.3p327)。

例如,在对 lib 进行一些更改后,我可能会忘记重新启动 delay_job,这让我很担心,导致我在意识到这一点之前调试了几个小时。

我将以下内容添加到我的script/rails文件中,以允许问题中提供的代码在我们每次启动 rails 时执行,但不是每次工作人员启动时执行:

puts "cleaning up delayed job pid..."
dj_pid_path = File.expand_path('../../tmp/pids/delayed_job.pid',  __FILE__)
begin
  File.delete(dj_pid_path)
rescue Errno::ENOENT # file does not exist
end
puts "delayed_job ready."

不过,我面临的一个小缺点是它也会被调用rails generate。我没有花太多时间为此寻找解决方案,但欢迎提出建议:-)

请注意,如果您使用的是独角兽,您可能希望在调用config/unicorn.rb之前添加相同的代码。before_fork

-- 已编辑: 在对上述解决方案进行了更多尝试之后,我最终执行了以下操作:

我创建了一个script/start_delayed_job.rb包含以下内容的文件:

puts "cleaning up delayed job pid..."
dj_pid_path = File.expand_path('../../tmp/pids/delayed_job.pid',  __FILE__)

def kill_delayed(path)
  begin
    pid = File.read(path).strip
    Process.kill(0, pid.to_i)
    false
  rescue
    true
  end
end

kill_delayed(dj_pid_path)

begin
  File.delete(dj_pid_path)
rescue Errno::ENOENT # file does not exist
end

# spawn delayed
env = ARGV[1]
puts "spawing delayed job in the same env: #{env}" 

# edited, next line has been replaced with the following on in order to ensure delayed job is running in the same environment as the one that spawned it
#Process.spawn("ruby script/delayed_job start")
system({ "RAILS_ENV" => env}, "ruby script/delayed_job start")

puts "delayed_job ready."

现在我可以在任何我想要的地方使用这个文件,包括“script/rails”和“config/unicorn.rb”,方法是:

# in top of script/rails
START_DELAYED_PATH = File.expand_path('../start_delayed_job',  __FILE__)
require "#{START_DELAYED_PATH}"

# in config/unicorn.rb, before before_fork, different expand_path
START_DELAYED_PATH = File.expand_path('../../script/start_delayed_job',  __FILE__)
require "#{START_DELAYED_PATH}"
于 2013-02-22T10:02:09.570 回答
0

不是很好,但有效

免责声明:我说不好,因为这会导致定期重启,这对许多人来说是不可取的。并且简单地尝试启动可能会导致问题,因为如果创建重复实例,DJ 的实现可能会锁定队列。

您可以安排cron定期运行的任务以启动相关作业。由于 DJ 在作业已经运行时将启动命令视为无操作,因此它可以正常工作。这种方法还可以处理 DJ 因主机重启以外的其他原因而死亡的情况。

# crontab example 
0 * * * * /bin/bash -l -c 'cd /var/your-app/releases/20151207224034 && RAILS_ENV=production bundle exec script/delayed_job --queue=default -i=1 restart'

如果您使用的是这样的 gem,whenever那非常简单。

every 1.hour do
  script "delayed_job --queue=default -i=1 restart"
  script "delayed_job --queue=lowpri -i=2 restart"
end
于 2015-12-11T16:18:28.687 回答