Puma 服务器在发送 capistrano "puma:restart" 信号后挂起

Puma server hangs after capistrano "puma:restart" signal is sent

当我第一次使用 cap [env] deploy 部署我的应用程序时,一切都按预期进行。代码已部署,puma 服务器已成功启动 puma:start

puma 启动的 capistrano 输出

 * 2015-01-09 12:19:37 executing `puma:start'
 * executing "cd /path/to/app/current && bundle exec puma -q -d -e production -C ./config/puma/production.rb"
   servers: ["example.com"]
   [example.com] executing command
** [out :: example.com] Puma starting in single mode...
** [out :: example.com] * Version 2.9.2 (ruby 2.1.5-p273), codename: Team High Five
** [out :: example.com] * Min threads: 0, max threads: 16
** [out :: example.com] * Environment: production
** [out :: example.com] * Listening on unix:///path/to/app/shared/sockets/puma.sock
** [out :: example.com] * Daemonizing...

如果我更改代码并尝试重新部署,而不是调用 puma:start,capistrano 会调用 puma:restart,这就像成功一样,但实际上并没有重新启动 puma。

 * 2015-01-09 12:27:56 executing `puma:restart'
 * executing "cd /path/to/app/current && bundle exec pumactl -S /path/to/app/shared/sockets/puma.state restart"
   servers: ["example.com"]
   [example.com] executing command
** [out :: example.com] Command restart sent success

此时,如果我刷新网页,我会收到 504 Gateway Time-out 错误。它与 this issue..

非常相似

正如那个人所建议的那样,如果我将 workers 1 添加到我的 puma 配置文件中,重新启动会起作用,但 start/stop 不会。

在我目前的状态下(没有工人),如果我这样做 cap [env] puma:stop,它不会阻止 puma。它还 NOT 删除以下任何文件:

/path/to/app/shared/pids/puma.pid
/path/to/app/shared/sockets/puma.sock
/path/to/app/shared/sockets/puma.state

重要提示

在我的 Rails 服务器中,我使用 ActionController::Live 和 Rails 4.1。我使用 Javascript / Redis 连接到事件流。我在我的 nginx 错误日志中注意到了这一点:

nginx错误日志

2015/01/09 12:29:32 [error] 8992#0: *371 upstream timed out (110: 
Connection timed out) while reading response header from upstream, 
client: [ip], server: example.com, request: "GET /build_configurations/refresh_workers HTTP/1.1", 
upstream: "http://unix:///path/to/app/shared/sockets/puma.sock/build_configurations
/refresh_workers", host: "example.com", referrer: "https://example.com/"

总而言之,我怎样才能成功地使用 cap [env] deploy 将更新部署到我的代码,同时让 puma 启动和重新启动正常?

更新

我发现 this issue 谈到用 ActionController::Live 重启 puma,但似乎没有解决方案。

使用我在 this other Stack Overflow answer 中找到的信息,我能够实施似乎可以解决此问题的检测信号。我自己还没有完全理解所有的机制,但我从一个初始化器开始心跳:

config/initializers/redis.rb

REDIS = Redis.new(url: "redist://localhost:6379")

heartbeat_thread = Thread.new do
  while true
    REDIS.publish('heartbeat','thump')
    sleep 2.seconds
  end
end

at_exit do
  # not sure this is needed, but just in case
  heartbeat_thread.kill
  REDIS.quit
end

我的控制器有:

def build_status_events
  response.headers["Content-Type"] = "text/event-stream"
  redis = Redis.new(url: "redist://localhost:6379")

  # blocks the current thread
  redis.psubscribe(['my_event', 'heartbeat']) do |on|
    on.pmessage do |pattern, event, data|
      response.stream.write("event: #{event}\n")
      if event == 'heartbeat'
        response.stream.write("data: heartbeat\n\n")
      else
        response.stream.write("data: #{data.to_json}\n\n")
      end
    end
  end
rescue IOError
  logger.info 'Events stream closed'
ensure
  logger.info 'Stopping Events streaming thread'
  redis.quit
  response.stream.close
end

我相信发生的情况是心跳被发布,如果出现错误,将调用确保块并关闭订阅。然后 puma 按预期重新启动。如果谁有更好的解决方案,或者更多的信息,欢迎评论或者补充答案。