Unicorn 未通过 Rails 应用程序(Capistrano、Nginx)的新部署获取更改
Unicorn doesn't pick up changes with new deploy of Rails app (Capistrano, Nginx)
我是部署新手,所以这可能是菜鸟犯的错误,但就是这样。
我有一个 Rails 4 应用程序,我正在使用 Capistrano、Unicorn 和 Nginx 的组合部署到 Linux 服务器。部署脚本 运行 没问题,应用程序现在可以通过所需的 IP 访问,这太棒了。问题是,a) Unicorn 不会在部署后重新启动(至少,PID 不会改变)并且 b) 毫不奇怪,新的更改不会反映在可用的应用程序中。除了完全停止并重新启动独角兽以刷新它之外,我似乎无法做任何事情。如果我这样做,那么变化就被拾取了,但是这个过程显然不理想。
手动地,如果我 运行 kill -s HUP $UNICORN_PID
那么 worker 的 pids 会改变,但 master 不会,并且更改不会被拾取(显然它们应该是);使用 USR2
似乎对当前进程没有影响。
根据其他具有类似问题的堆栈溢出问题的建议,这是我正在使用的独角兽初始化脚本:
set -e
USAGE="Usage: [=11=] <start|stop|restart|upgrade|rotate|force-stop>"
# app settings
USER="deploy"
APP_NAME="app_name"
APP_ROOT="/path/to/$APP_NAME"
ENV="production"
# environment settings
PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH"
CMD="cd $APP_ROOT/current && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
PID="$APP_ROOT/shared/pids/unicorn.pid"
OLD_PID="$PID.oldbin"
TIMEOUT=${TIMEOUT-60}
# make sure the app exists
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill - `cat $PID`
}
oldsig () {
test -s $OLD_PID && kill - `cat $OLD_PID`
}
case in
start)
sig 0 && echo >&2 "Already running" && exit 0
echo "Starting $APP_NAME"
su - $USER -c "$CMD"
;;
stop)
echo "Stopping $APP_NAME"
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
echo "Force stopping $APP_NAME"
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo "reloaded $APP_NAME" && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
run "$CMD"
;;
upgrade)
if sig USR2 && sleep 2 && 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"
su - $USER -c "$CMD"
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 $USAGE
exit 1
;;
esac
使用此脚本,start
和 stop
按预期工作,但 reload
/restart
什么都不做(它们打印预期的输出但不更改运行ning pids) 和 upgrade
失败。根据报错日志,是因为第一个master还是运行ning(ArgumentError: Already running on PID: $PID
).
这是我的 unicorn.rb:
app_path = File.expand_path("../..", __FILE__)
working_directory "#{app_path}"
pid "#{app_path}/../../shared/pids/unicorn.pid"
# listen
listen "#{app_path}/../../shared/sockets/unicorn.sock", :backlog => 64
# logging
stderr_path "#{app_path}/../../shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/../../shared/log/unicorn.stdout.log"
# workers
worker_processes 3
# use correct Gemfile on restarts
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{working_directory}/Gemfile"
end
# preload
preload_app false
before_fork do |server, worker|
old_pid = "#{app_path}/shared/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
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
非常感谢任何帮助,谢谢!
这很难说,因为我以前没有遇到过这个特殊问题,但我的直觉是这是你的问题:
app_path = File.expand_path("../..", __FILE__)
working_directory "#{app_path}"
每次部署时,Capistrano 都会在 releases/<timestamp>
位置为您的应用程序创建一个新目录。然后它更新 current
符号链接以指向这个最新版本目录。
在您的情况下,您可能错误地告诉 Unicorn 使用 releases/<timestamp>
作为它的 working_directory
。 (SSH 到服务器并检查 unicorn.rb
的内容以确定。)相反,你应该做的是指向 current
。这样你就不必停下来冷启动独角兽来让它看到新的工作目录。
# Since "current" is a symlink to the current release,
# Unicorn will always see the latest code.
working_directory "/var/www/my-app/current"
我建议重写您的 unicorn.rb,这样您就不会使用相对路径。而是将绝对路径硬编码到 current
和 shared
。这样做是可以的,因为这些路径对于每个版本都将保持不变。
行
ENV="production"
我觉得非常可疑。我怀疑它想成为
RAILS_ENV="production".
没有这个就不会rails醒来不知道是什么环境了?
我是部署新手,所以这可能是菜鸟犯的错误,但就是这样。
我有一个 Rails 4 应用程序,我正在使用 Capistrano、Unicorn 和 Nginx 的组合部署到 Linux 服务器。部署脚本 运行 没问题,应用程序现在可以通过所需的 IP 访问,这太棒了。问题是,a) Unicorn 不会在部署后重新启动(至少,PID 不会改变)并且 b) 毫不奇怪,新的更改不会反映在可用的应用程序中。除了完全停止并重新启动独角兽以刷新它之外,我似乎无法做任何事情。如果我这样做,那么变化就被拾取了,但是这个过程显然不理想。
手动地,如果我 运行 kill -s HUP $UNICORN_PID
那么 worker 的 pids 会改变,但 master 不会,并且更改不会被拾取(显然它们应该是);使用 USR2
似乎对当前进程没有影响。
根据其他具有类似问题的堆栈溢出问题的建议,这是我正在使用的独角兽初始化脚本:
set -e
USAGE="Usage: [=11=] <start|stop|restart|upgrade|rotate|force-stop>"
# app settings
USER="deploy"
APP_NAME="app_name"
APP_ROOT="/path/to/$APP_NAME"
ENV="production"
# environment settings
PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH"
CMD="cd $APP_ROOT/current && bundle exec unicorn -c config/unicorn.rb -E $ENV -D"
PID="$APP_ROOT/shared/pids/unicorn.pid"
OLD_PID="$PID.oldbin"
TIMEOUT=${TIMEOUT-60}
# make sure the app exists
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill - `cat $PID`
}
oldsig () {
test -s $OLD_PID && kill - `cat $OLD_PID`
}
case in
start)
sig 0 && echo >&2 "Already running" && exit 0
echo "Starting $APP_NAME"
su - $USER -c "$CMD"
;;
stop)
echo "Stopping $APP_NAME"
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
echo "Force stopping $APP_NAME"
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo "reloaded $APP_NAME" && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
run "$CMD"
;;
upgrade)
if sig USR2 && sleep 2 && 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"
su - $USER -c "$CMD"
;;
rotate)
sig USR1 && echo rotated logs OK && exit 0
echo >&2 "Couldn't rotate logs" && exit 1
;;
*)
echo >&2 $USAGE
exit 1
;;
esac
使用此脚本,start
和 stop
按预期工作,但 reload
/restart
什么都不做(它们打印预期的输出但不更改运行ning pids) 和 upgrade
失败。根据报错日志,是因为第一个master还是运行ning(ArgumentError: Already running on PID: $PID
).
这是我的 unicorn.rb:
app_path = File.expand_path("../..", __FILE__)
working_directory "#{app_path}"
pid "#{app_path}/../../shared/pids/unicorn.pid"
# listen
listen "#{app_path}/../../shared/sockets/unicorn.sock", :backlog => 64
# logging
stderr_path "#{app_path}/../../shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/../../shared/log/unicorn.stdout.log"
# workers
worker_processes 3
# use correct Gemfile on restarts
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{working_directory}/Gemfile"
end
# preload
preload_app false
before_fork do |server, worker|
old_pid = "#{app_path}/shared/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
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
非常感谢任何帮助,谢谢!
这很难说,因为我以前没有遇到过这个特殊问题,但我的直觉是这是你的问题:
app_path = File.expand_path("../..", __FILE__)
working_directory "#{app_path}"
每次部署时,Capistrano 都会在 releases/<timestamp>
位置为您的应用程序创建一个新目录。然后它更新 current
符号链接以指向这个最新版本目录。
在您的情况下,您可能错误地告诉 Unicorn 使用 releases/<timestamp>
作为它的 working_directory
。 (SSH 到服务器并检查 unicorn.rb
的内容以确定。)相反,你应该做的是指向 current
。这样你就不必停下来冷启动独角兽来让它看到新的工作目录。
# Since "current" is a symlink to the current release,
# Unicorn will always see the latest code.
working_directory "/var/www/my-app/current"
我建议重写您的 unicorn.rb,这样您就不会使用相对路径。而是将绝对路径硬编码到 current
和 shared
。这样做是可以的,因为这些路径对于每个版本都将保持不变。
行
ENV="production"
我觉得非常可疑。我怀疑它想成为
RAILS_ENV="production".
没有这个就不会rails醒来不知道是什么环境了?