使用Capistrano启动后台任务

20

我的RubyOnRails应用需要在Capistrano部署结束时启动后台作业。为此,我在deploy.rb中尝试了以下内容:

run "nohup #{current_path}/script/runner -e production 'Scheduler.start' &", :pty => true
有时这个方法可行,但大部分时间它无法启动进程 (= 不会在 ps -aux 中列出)。并且没有错误消息。同时,在 home 目录和 rails 应用程序目录中都没有 nohup.out 文件。
我尝试在 scheduler.rb 中使用 trap('SIGHUP', 'IGNORE') 替换 nohup,但结果相同。
唯一的方法是删除 ":pty => true" 并在 "cap deploy" 结束时手动 Ctrl-C。但我不喜欢这种方式...
还有其他调用 Scheduler.start 的机会吗?或者能获得更多错误消息吗?
我正在使用 Rails 2.3.2、Capistrano 2.5.8 和 Ubuntu Hardy 服务器。

有什么提示吗?我还在努力重新启动后台作业... - Georg Ledermann
4个回答

18

使用 :pty => true 选项启动用户 shell 时,其启动脚本(例如 bashrc 等)通常不会被加载。由于缺少依赖环境变量,我的 Ruby 程序在启动后立即退出。

如果没有 :pty => true 选项,就像您在问题中描述的那样,Capistrano 会挂起等待进程退出。你需要重定向标准输出和标准错误输出才能使其立即返回。

run 'nohup ruby -e "sleep 5" &' # hangs for 5 seconds
run 'nohup ruby -e "sleep 5" > /dev/null &' # hangs for 5 seconds
run 'nohup ruby -e "sleep 5" > /dev/null 2>&1 &' # returns immediately. good.

如果您的后台任务仍然无法运行,请尝试将stdout和stderr重定向到日志文件,以便您可以调查输出。


3
我曾经花了一整天的时间来解决完全相同的问题。按照建议将输出重定向解决了这个问题。 - randomuser

6

我想分享我的解决方案,它也适用于执行多个命令。我尝试了许多在线找到的其他变体,包括“sleep N”技巧。

run("nohup sh -c 'cd #{release_path} && bundle exec rake task_namespace:task_name RAILS_ENV=production > ~/shared/log/<rakelog>.log &' > /dev/null 2>&1", :pty => true)

这是一个重复的回答在Capistrano任务中启动后台进程,但我希望确保其他人和我自己可以通过Google找到这个解决方案。


那帮了我。谢谢。 - Mark

1
如果这个任务调度器有一个 -d 开关,它就可以工作。例如,Passenger Standalone 有一个 -d 选项,可以将其作为守护进程启动。
namespace :passenger_standalone do
  task :start do
    run "cd #{current_path} && passenger start -e #{rails_env} -d"
  end
  task :stop do
    run "cd #{current_path} && RAILS_ENV=#{rails_env} passenger stop"
  end
  task :restart do
    stop
    start
  end
end

1

你想让你的调度任务在后台持续运行,并在运行Capistrano时重新启动吗?

如果是这样,那么我使用runithttp://smarden.sunsite.dk/runit/和DelayedJob http://github.com/Shopify/delayed_job/tree/master实现。

  1. 以不替换 init 模式安装 runit。
  2. 将您的后台任务作为 runit 服务添加,并从 runit 添加日志监视器。
  3. 让 Capistrano 调用 sudo sv kill job_name 来杀死和重启任务。

我的后台任务是一个 Rails 插件 DelayedJob 的实例,它处理 Rails 后台任务。我每次使用 Capistrano 部署时都会将其杀死,以便重新启动更新后的代码库。

这被证明非常可靠。

希望对你有所帮助,

Larry


是的,调度程序应在后台持续运行,并且应在每次部署时重新启动。我在调度程序中使用了DelayedJob - 还有一些自己的东西。因为通过script/runner启动有时会出现Capistrano问题(并且如果我通过SSH会话手动启动它,则总是有效),所以我认为Capistrano只存在一个小问题- 所以如果没有真正需要,我不想转移到runit...但非常感谢您的答复,Larry! - Georg Ledermann
自动重启怎么处理?这是runit负责的另一件事。此外,如果它死掉了,还会重新启动。谢谢。 - Larry K
部署用户不应该具备“sudo”特权。在大多数部署中,部署用户与运行Rails应用程序的用户相同。授予该用户sudo权限是一个非常糟糕的想法,特别是考虑到最近Rails存在的安全问题,攻击者能够执行任意代码。 - platforms

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