0

I'm doing a Capistrano deployment of a Rails app. It's been a lot of fun for the most part.

After the deployment is complete (in deploy:restart), I would like to start the Rails server, watch the output for a while, and then hit Ctrl-C to send an interrupt, thereby stopping the output, and proceeding the deploy:cleanup task. At one point it seemed like this was working, except that it appeared to be considering the interrupt to be an exception and so was saying it "Cannot Start the Rails Server" even though it was actually started and running. I wanted to rescue the interrupt, and so wrote the following, based in part on another thread here:

namespace :deploy do
    task :restart, :roles => :app, :except => { :no_release => true } do 
      begin
        logger.info 'Attempting to Start the Rails Server'
        run "cd #{release_path} && script/rails s"
      rescue SystemExit, Interrupt
        logger.info %q[Au revoir! And don't worry. The server will continue running just fine without you hanging around looking over it's shoulder.]
      rescue Exception => error
        logger.important 'Cannot Start the Rails Server. This may be a problem.'
        logger.info "#{error}"
      end
    end
  end

However, this doesn't work. Before I hit Ctrl-C, while the server is still running, as I would expect, I'm getting this sort of thing:

 ** [out :: server.example.com] Started GET "/assets/bootstrap.js?body=1" for 178.120.25.53 at 2012-07-09 19:10:53 +0000
 ** [out :: server.example.com] Served asset /bootstrap.js - 200 OK (11ms)

And then after I send the interrupt, I'm getting this:

 ** Au revoir! And don't worry. The server will continue running just fine without you hanging around looking over it's shoulder.
    triggering after callbacks for `deploy:restart'
  * executing `deploy:cleanup'
  * executing "ls -xt /srv/www/my_project/releases"
    servers: ["server.example.com"]
    [server.example.com] executing command
    command finished in 774ms
 ** keeping 1 of 2 deployed releases
  * executing "rm -rf /srv/www/my_project/releases/20120709190209"
    servers: ["server.example.com"]
    [server.example.com] executing command
    command finished in 811ms

Which looks right...but as it turns out, Rails is not, in fact, still running, as a grep of the processes before and after reveals.

Before Ctrl-C, I see both the Capistrano command (19358), and the Rails server it started (19507):

user@server.example.com:~$ ps ax | grep rails | grep -v grep
19358 pts/1    Ss+  0:01 bash -c cd /srv/www/my_project/releases/20120709190521 && script/rails s
19507 pts/1    Sl+  0:41 ruby script/rails s

After Ctrl-C, the Rails server is still there, or it appears to be:

user@server.example.com:~$ ps ax | grep rails | grep -v grep
19507 ?        Sl   0:41 ruby script/rails s

But after I attempt to hit the site in a web browser, it disappears! Weird eh?

user@server.example.com:~$ ps ax | grep rails | grep -v grep
user@server.example.com:~$ [no output; returned to prompt]

So, my question is: How do I do this thing? How do sever the communication between the running Rails process and Capistrano, allow Capistrano to move on to it's remaining tasks, and then give me back my terminal prompt, without stopping the Rails server? Any help would be appreciated.

4

2 回答 2

0

您可以在 Ruby 中使用 Signal.trap 来捕捉 Ctrl-C。但是我不确定如何使用 Capistrano 做你需要做的事情——你想产生一个在 Capistrano 进程结束时不会终止的孙进程。

于 2012-07-16T12:11:30.390 回答
0

我现在意识到这是一个 PEBCAC 错误。我的 Capistrano 脚本中的 Begin-Rescue-End 块没有捕获(拯救)我的入站Ctrl-C。它只是将它传递给正在运行的 Rails 服务器进程,该进程顺从地以 SystemExit 退出,然后将其传递回 Capistrano 脚本,然后捕获出站异常。到那时,这是一笔交易。无量抓处理出境Capistrano 脚本上下文中的异常会阻止 Rails 服务器停止。所以,我现在明白为什么它不起作用了。但我仍然很好奇是否有办法做我想做的事情。这意味着在 Capistrano 的某个地方捕获我的入站中断并在它可以传递到服务器之前对其进行处理。

于 2012-07-12T18:06:15.587 回答