我正在学习使用
Capistrano
部署演示 Rails 应用程序,并使用 Puma 作为应用程序服务器和相应的 Nginx Web 服务器。我已在名为 _stage.rb
的文件中设置了必要的 puma 设置配置,并将 puma
设置为 systemd
服务,这是我符号链接为 /etc/init.d/puma_myarticles_staging
的可执行文件。可执行文件名为 puma_init.sh.erb
,后来被写入远程服务器作为 puma_init.sh
,看起来像,
#!/usr/bin/env bash
PATH=/usr/local/bin:/usr/local/sbin/:/sbin:/usr/sbin:/bin:/usr/bin
DESC="Puma rack web server"
NAME=puma_<%=fetch(:full_app_name)%>
SCRIPT_NAME=/etc/init.d/${NAME}
APP_ROOT=<%=current_path%>
PIDFILE=<%= fetch(:puma_pid) %>
STATE_FILE=<%= fetch(:puma_state) %>
log_daemon_msg() { echo "$@"; }
log_end_msg() { [ $1 -eq 0 ] && RES=OK; logger ${RES:=FAIL}; }
run_pumactl(){
[ $# -lt 1 ] && echo "$# params were given, Expected 1" && exit 1
cd ${APP_ROOT} && <%= fetch(:rbenv_prefix) %> bundle exec pumactl -F <%=fetch(:puma_conf)%> $1
}
# Function that starts the puma
#
start_task() {
if [ -e ${PIDFILE} ]; then
PID=`cat ${PIDFILE}`
# If the puma isn't running, run it, otherwise restart it.
if [ "`ps -A -o pid= | grep -c ${PID}`" -eq 0 ]; then
do_start_task
else
restart_task
fi
else
do_start_task
fi
}
do_start_task() {
log_daemon_msg "--> Woke up puma ${APP_ROOT}"
run_pumactl start
}
# Function that stops the daemon/service
#
stop_task() {
log_daemon_msg "--> Stopping puma in path: ${APP_ROOT} ..."
if [ -e ${PIDFILE} ]; then
PID=`cat ${PIDFILE}`
if [ "`ps -A -o pid= | grep -c ${PID}`" -eq 0 ]; then
log_daemon_msg "--> Puma isn't running in path: ${APP_ROOT}."
else
log_daemon_msg "--> About to kill puma with PID: `cat $PIDFILE` ..."
if [ "`ps -A -o pid= | grep -c ${PID}`" -eq 0 ]; then
log_daemon_msg "--> Puma isn't running in path: ${APP_ROOT}."
return 0
else
run_pumactl stop
log_daemon_msg "--> Waiting for status ..."
sleep 5
if [ "`ps -A -o pid= | grep -c ${PID}`" -eq 0 ]; then
log_daemon_msg "--> Puma with pid ${PID} stopped successfully."
rm -f ${PIDFILE} ${STATE_FILE}
else
log_daemon_msg "--> Unable to stop puma with pid ${PID}."
fi
fi
fi
else
log_daemon_msg "--> Puma isn't running in path: ${APP_ROOT}."
fi
return 0
}
# Function that sends a SIGUSR2 to the daemon/service
#
restart_task() {
if [ -e ${PIDFILE} ]; then
log_daemon_msg "--> About to restart puma in path: ${APP_ROOT} ..."
run_pumactl restart
else
log_daemon_msg "--> Your puma was never playing... Let's get it out there first ..."
start_task
fi
return 0
}
#
# Function that sends a SIGUSR2 to the daemon/service
#
status_task() {
if [ -e ${PIDFILE} ]; then
log_daemon_msg "--> About to status puma ${APP_ROOT} ..."
run_pumactl status
else
log_daemon_msg "---> Puma isn't running in path: ${APP_ROOT}."
fi
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting ${DESC}" "${NAME} ..."
start_task
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping ${DESC}" "${NAME} ..."
stop_task
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
log_daemon_msg "Status ${DESC}" "${NAME} ..."
status_task
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart)
log_daemon_msg "Restarting ${DESC}" "${NAME} ..."
restart_task
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
*)
echo "Usage:" >&2
echo " ${SCRIPT_NAME} {start|stop|status|restart}" >&2
exit 3
;;
esac
:
然而,由于未知的原因,Puma 工作人员并未作为一个进程启动。我的
puma.rb.erb
后来写成puma.rb
是,
#!/usr/bin/env puma
directory '<%= current_path %>'
environment '<%= fetch(:rails_env) %>'
pidfile '<%= fetch(:puma_pid) %>'
state_path '<%= fetch(:puma_state) %>'
stdout_redirect '<%= fetch(:puma_access_log) %>', '<%= fetch(:puma_error_log) %>', true
daemonize
threads <%= fetch(:puma_threads).join(', ') %>
bind '<%= fetch(:puma_bind) %>'
activate_control_app '<%= fetch(:puma_default_control_app) %>'
workers '<%= fetch(:puma_workers) %>'
preload_app!
on_worker_boot do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.establish_connection
end
end
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
我从名为
_stage.rb
的文件中获取所有美洲狮配置,看起来像,
set :stage, :staging
set :branch, :staging
set :server_port, 80
set :full_app_name, "#{fetch(:application)}_#{fetch(:stage)}"
set :rails_env, :staging
set :deploy_to, "/home/#{fetch(:deploy_user)}/#{fetch(:full_app_name)}"
set :puma_user, fetch(:deploy_user)
set :puma_state, "#{shared_path}/tmp/states/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_rackup, -> { File.join(current_path, 'config.ru')}
set :puma_bind, "unix://#{shared_path}/tmp/sockets/puma.#{fetch(:full_app_name)}.sock"
set :puma_default_control_app, "unix://#{shared_path}/tmp/sockets/pumactl.#{fetch(:full_app_name)}.sock"
set :puma_conf, "#{shared_path}/config/puma.rb"
set :puma_workers, 4
set :puma_threads, [4, 8]
set :puma_role, :app
set :puma_env, :staging
set :puma_preload_app, true
set :puma_enable_socket_service, true
set :puma_access_log, "#{shared_path}/log/puma_access.log"
set :puma_error_log, "#{shared_path}/log/puma_error.log"
set :nginx_access_log, "#{shared_path}/log/nginx_access.log"
set :nginx_error_log, "#{shared_path}/log/nginx_error.log"
当我以
/etc/init.d/puma_myarticles_staging start
启动 puma 服务时,它输出,
Starting Puma rack web server puma_myarticles_staging ...
--> Woke up puma /home/deployer/myarticles_staging/current
[1484] Puma starting in cluster mode...
[1484] * Version 3.12.6 (ruby 2.7.0-p0), codename: Llamas in Pajamas
[1484] * Min threads: 4, max threads: 8
[1484] * Environment: staging
[1484] * Process workers: 4
[1484] * Preloading application
/home/deployer/myarticles_staging/shared/bundle/ruby/2.7.0/gems/activerecord-5.2.8.1/lib/active_record/type.rb:27: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/home/deployer/myarticles_staging/shared/bundle/ruby/2.7.0/gems/activerecord-5.2.8.1/lib/active_record/type/adapter_specific_registry.rb:9: warning: The called method `add_modifier' is defined here
[1484] * Listening on unix:///home/deployer/myarticles_staging/shared/tmp/sockets/puma.myarticles_staging.sock
[1484] ! WARNING: Detected 1 Thread(s) started in app boot:
[1484] ! #<Thread:0x0000561adf6c0228 /home/deployer/myarticles_staging/shared/bundle/ruby/2.7.0/gems/activerecord-5.2.8.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:299 sleep> - /home/deployer/myarticles_staging/shared/bundle/ruby/2.7.0/gems/activerecord-5.2.8.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:301:in `sleep'
[1484] * Daemonizing...
不留下新的 puma pid 或状态文件。最终,当我检查
puma.pid
和 puma.state
没有文件被写入时,puma 服务人员没有启动。当我运行 rbenv exec bundle exec rails s
在 current_path
上手动测试时,它起作用了。
我使用它输出的
systemd
检查了被妖魔化为 ps ax | grep puma
服务的 puma 进程,
1516 pts/0 S+ 0:00 grep --color=auto puma
对我可能做错的事情有什么建议吗? TIA
也许问题在于 puma 的启动方式。我很确定这里没有 Puma bug。 您还没有发布有关 systemctl 设置的任何详细信息,但最佳实践是使用用户服务文件,这样 puma 将始终在启动时启动,并且不需要密码
我使用的标准 puma 配置是这样的
# Puma can serve each request in a thread from an internal thread pool.
# The `threads` method setting takes two numbers: a minimum and maximum.
# Any libraries that use thread pools should be configured to match
# the maximum value specified for Puma. Default is set to 5 threads for minimum
# and maximum; this matches the default thread size of Active Record.
#
max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
threads min_threads_count, max_threads_count
# Change to match your CPU core count
workers 0
# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
port ENV.fetch("PORT") { 3000 }
# Specifies the `environment` that Puma will run in.
#
rails_env = ENV['RAILS_ENV'] || "production"
environment rails_env
app_dir = File.expand_path("../..", __FILE__)
#shared_dir = "#{app_dir}/shared"
shared_dir = "/home/project/apps/comtech/shared" # Use your projects path
# Specifies the `pidfile` that Puma will use.
#pidfile ENV.fetch("PIDFILE") { "pids/server.pid" }
pidfile "#{shared_dir}/pids/puma.pid"
state_path "#{shared_dir}/pids/puma.state"
activate_control_app
# Set up socket location
bind "unix://#{shared_dir}/sockets/comtech_puma.sock"
on_worker_boot do
require "active_record"
ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
ActiveRecord::Base.establish_connection(YAML.load_file("#{app_dir}/config/database.yml")[rails_env])
end
# Specifies the number of `workers` to boot in clustered mode.
# Workers are forked web server processes. If using threads and workers together
# the concurrency of the application would be max `threads` * `workers`.
# Workers do not work on JRuby or Windows (both of which do not support
# processes).
#
# workers ENV.fetch("WEB_CONCURRENCY") { 2 }
# Use the `preload_app!` method when specifying a `workers` number.
# This directive tells Puma to first boot the application and load code
# before forking the application. This takes advantage of Copy On Write
# process behavior so workers use less memory.
#
# preload_app!
# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart
显然,您需要将
ENVIRONMENT
变量设置为在服务器上暂存
相应调整 pids 文件夹以使用 tmp。
如果没有更多信息,真的无法提供更多帮助