Starting background tasks with Capistrano

2019-01-22 19:28发布

问题:

For my RubyOnRails-App I have to start a background job at the end of Capistrano deployment. For this, I tried the following in deploy.rb:

run "nohup #{current_path}/script/runner -e production 'Scheduler.start' &", :pty => true

Sometimes this works, but most of the time it does not start the process (= not listed in ps -aux). And there are no error messages. And there is no nohup.out, not in the home directory and not in the rails app directory.

I tried using trap('SIGHUP', 'IGNORE') in scheduler.rb instead of nohup, but the result is the same.

The only way to get it work is removing the ":pty => true" and do a manual Ctrl-C at the end of "cap deploy". But I don't like this...

Are there any other chances to invoke this Scheduler.start? Or to get some more error messages?

I'm using Rails 2.3.2, Capistrano 2.5.8, Ubuntu Hardy on the Server

回答1:

With :pty => true, user shell start-up scripts (e.g. bashrc, etc.) are (usually) not loaded. My ruby program exited right after launching because of the lack of dependent environment variables.

Without :pty => true, as you described in the question, capistrano hangs there waiting for the process to exit. You'll need to redirect both stdout and stderr to make it return immediately.

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.

If your background task still doesn't run. Try redirecting stdout and stderr to a log file so that you can investigate the output.



回答2:

I'd like to share my solution which also works when executing multiple commands. I tried many other variants found online, including the "sleep N" hack.

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)

This is a dup response launching background process in capistrano task but want to make sure others and myself can google for this solution.



回答3:

Do you want your Scheduler job to run continually in the background and get restarted when you run Capistrano?

If so, then for that I use runit http://smarden.sunsite.dk/runit/ and DelayedJob http://github.com/Shopify/delayed_job/tree/master

  1. Install runit in the mode of not replacing init
  2. Add your background job as a runit service and add the log monitor for it from runit.
  3. Have Capistrano call sudo sv kill job_name to kill and restart the job.

My backround job is an instance of the Rails plugin DelayedJob which handles background Rails tasks. I kill it with every Capistrano deploy so it will restart with the updated code base.

This has proved to be very reliable.

HTH,

Larry



回答4:

If this task scheduler has a -d switch it will work. For example passenger standalone has a -d option to start it as a demonized process.

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