Heroku+Rails4+Unicorn 反复崩溃,日志中没有有用的输出

Heroku+Rails4+Unicorn Repeated Crashes With No Helpful Output in Log

我在 Heroku 上 运行 数十个 Rails 应用程序,它们的代码非常相似,配置几乎相同。这个特定的应用程序在启动后立即崩溃。好像这还不够糟糕,日志中确实 nothing 表明出了什么问题。这是一个日志示例。

2016-01-14T05:56:13.776324+00:00 heroku[api]: Set LOG_LEVEL, SECRET_TOKEN config vars by karl@kandrsoftware.com
2016-01-14T05:56:13.776324+00:00 heroku[api]: Release v13 created by karl@kandrsoftware.com
2016-01-14T05:56:13.913292+00:00 heroku[web.1]: State changed from crashed to starting
2016-01-14T05:56:16.422157+00:00 heroku[web.1]: Starting process with command `bundle exec unicorn -p 32001 -c ./config/unicorn.rb`
2016-01-14T05:56:20.695481+00:00 heroku[web.1]: State changed from starting to crashed
2016-01-14T05:56:20.692142+00:00 heroku[web.1]: Process exited with status 1
2016-01-14T05:56:37.932488+00:00 heroku[web.1]: State changed from crashed to starting
2016-01-14T05:56:41.228603+00:00 heroku[web.1]: Starting process with command `bundle exec unicorn -p 17696 -c ./config/unicorn.rb`
2016-01-14T05:56:47.053145+00:00 heroku[web.1]: Process exited with status 1
2016-01-14T05:56:47.077114+00:00 heroku[web.1]: State changed from starting to crashed

这是我的 Procfile

web:     bundle exec unicorn -p $PORT -c ./config/unicorn.rb
worker:  bundle exec sidekiq -C config/sidekiq.yml

这是我的 unicorn.rb

pid "tmp/pids/unicorn.pid"
stdout_path "log/unicorn.log"
stderr_path "log/unicorn-err.log"

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 30
preload_app true

require 'fileutils'
FileUtils.mkdir_p 'tmp/pids/' unless File.exist? 'tmp/pids/'
FileUtils.mkdir_p 'log/' unless File.exist? 'log/'

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    Rails.logger.info('Disconnected from ActiveRecord')
  end

  sleep 1
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    Rails.logger.info('Connected to ActiveRecord')
  end
end

我不明白我错过了什么。

我尝试使用 RAILS_ENV=productionheroku local 进行故障排除,应用程序启动正常。

使用 heroku run bash 在 Heroku 上登录 bash 允许我从 Heroku 上的 CLI 启动应用程序就好了。

~ $ cat Procfile 
web:     bundle exec unicorn -p $PORT -c ./config/unicorn.rb
~ $ echo $PORT
9446
~ $ bundle exec unicorn -p $PORT -c ./config/unicorn.rb
~ $ 
2016-01-14T07:02:30.618120+00:00 heroku[api]: Starting process with command `bash` by karl@kandrsoftware.com
2016-01-14T07:02:33.058993+00:00 heroku[run.2370]: Awaiting client
2016-01-14T07:02:33.085689+00:00 heroku[run.2370]: Starting process with command `bash`
2016-01-14T07:02:33.501795+00:00 heroku[run.2370]: State changed from starting to up

啊!我想通了!

我能够看到 Heroku 上的独角兽日志是这样的:

~ $ less log/unicorn-err.log 

所以,原来是一个简单的缺少配置变量。

此外,日志记录和 PID 位置是从 Linode 上的应用程序 运行 中提取的,不应在 Heroku 配置文件中。

应该是这样的:

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 30
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
    Rails.logger.info('Disconnected from ActiveRecord')
  end

  sleep 1
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.establish_connection
    Rails.logger.info('Connected to ActiveRecord')
  end
end

(参考:Heroku Dev Center: Deploying Rails Applications with Unicorn

如果不通过 stdout_pathstderr_path 指令重定向输出,则可以从 heroku logs -t.

中看到错误消息

又一个我妨碍自己的例子。