我想知道在新代码推送后优雅地重启delayed_job消费者的最佳方法是什么?我正在使用capistrano推送代码,我知道有重启的命令,但如果当前正在运行的作业,该命令要么挂起(我的部署需要永久),要么强行退出当前正在运行的作业,我会丢失数据。
理想情况下,我希望我的部署发生如下:
cap deploy
,版本2代码被推送到新服务器我试图通过检查代码的当前版本来插入一些代码以在作业运行之前重新启动,但每次我这样做时,它就会死掉并且实际上不会重新启动任何东西。示例代码如下:
def before(job)
# check to make sure that the version of code here is the right version of code
live_git_hash = LIVE_REVISION
local_git_hash = LOCAL_REVISION
if live_git_hash != local_git_hash
# get environment to reload in
environment = Rails.env # production, development, staging
# restart the delayed job system
%x("export RAILS_ENV=#{environment} && ./script/delayed_job restart")
end
end
它检测到它很好但它在shell调用时死掉了。有什么想法吗?
谢谢!
答案 0 :(得分:4)
提出了一个有效的解决方案。
我有一个基类,我所有延迟的作业都从名为BaseJob
继承:
class BaseJob
attr_accessor :live_hash
def before(job)
# check to make sure that the version of code here is the right version of code
resp = HTTParty.get("#{Rails.application.config.root_url}/revision")
self.live_hash = resp.body.strip
end
def should_perform()
return self.live_hash == GIT_REVISION
end
def perform()
if self.should_perform == true
self.safe_perform()
end
end
def safe_perform()
# override this method in subclasses
end
def success(job)
if self.should_perform == false
# log stats here about a failure
# enqueue a new job of the same kind
new_job = DelayedJob.new
new_job.priority = job.priority
new_job.handler = job.handler
new_job.queue = job.queue
new_job.run_at = job.run_at
new_job.save
job.delete
# restart the delayed job system
%x("export RAILS_ENV=#{Rails.env} && ./script/delayed_job stop")
else
# log stats here about a success
end
end
end
所有基类都继承自BaseJob
并覆盖safe_perform
以实际完成其工作。关于上述代码的一些假设:
Rails.application.config.root_url
指向您应用的根目录(即:www.myapp.com)/revision
的路线(即:www.myapp.com/revision)GIT_REVISION
的全局常量我最终做的是将git rev-parse HEAD
的输出放在一个文件中并用代码推送它。它会在启动时加载,因此它可以在Web版本以及delayed_job使用者中使用。
当我们通过Capistrano部署代码时,我们不再停止,启动或重新启动delayed_job使用者。我们在每分钟运行的消费者节点上安装一个cronjob,并确定delayed_job进程是否正在运行。如果不是,那么将产生一个新的。
由于所有这些,满足以下所有条件: