因此,将USR2发送到Unicorn非常棒 - 它会启动一个带有新代码副本的新主人,并自动获取任何更改。甜。我的问题是:我如何阻止老主人?显而易见的方式是在before_fork中:
before_fork do |server,worker|
old_pid = '/var/www/current/tmp/pids/unicorn.pid.oldbin'
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
end
问题在于,一旦新的主人(和新工人)产生,他们就会杀死旧的主人。因此,对网站的任何请求都只是坐在那里等待新工作人员启动,通常在整个Rails堆栈加载时持续几秒钟。
如果我删除了我的before_fork一切正常,我希望(从客户的角度来看):我可以整天重新加载我的浏览器,每个请求都快速填写,没有迹象表明新主人何时接管(除了看到我的代码更改现在出现了)。但是,旧的主人现在一直挂着,直到我手动发送一个退出。
据我所知,一旦工人完成装载并准备为客户服务,就没有回调。这真的是我正在寻找的回调。我总是可以在Rails中创建一个初始化程序,它可以查找一个老主人并杀死它,但这只会让我的心受到伤害。
一定有办法!
答案 0 :(得分:16)
我部分解决了这个问题:我看到的行为是由于没有使用preload_app true
造成的。如果你有这个设置,那么整个应用程序由主人加载,工人很快就会产生。因此,如果第一个工人此时杀死了老主人,那就没关系,因为所说的工人可以立即开始提出请求!
如果你不能使用preload_app true
那么你最好的选择可能就是将那个旧的pid-quit行为转移到Rails初始化程序中,这样第一个启动你的应用程序的工作者可以在Rails中杀死旧的主人已经启动并准备好处理请求。
答案 1 :(得分:8)
如果preload_app
为false
,似乎向Unicorn主机发送HUP信号是更好的选择。
来自http://unicorn.bogomips.org/SIGNALS.html:
HUP - 重新加载配置文件和 优雅地重启所有工人。如果 “preload_app”指令是假的( 默认),然后工人也会选择 任何应用程序代码更改时 重新启动。
答案 2 :(得分:3)
以下是我在before_fork块中的内容:
old_pid = "#{server.config[:pid]}.oldbin"
if old_pid != server.pid
begin
sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
Process.kill(sig, File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
end
end
要重新启动我的独角兽,我有一个bash脚本,它有一个这样的方法:
if sig USR2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
bash脚本发送一个USR2信号,该信号会分叉新的独角兽并创建旧的pid。然后它使用旧的pid向旧的独角兽发送QUIT信号。
这个过程非常有效,取自Where Unicorns go to die: Watching unicorn workers with monit,这是一个很好的资源。