Search code examples
ruby-on-railscapistranopuma

Capistrano puma:restart not working, but puma:start does


I am using Capistrano to deploy my Rails 5 app to AWS EC2 instance. When I type:

cap production deploy

Things go smoothly and the deployment is successful. However, the process of restarting puma is not working. The last task I see as:

puma:restart
      01 ~/.rvm/bin/rvm ruby-2.4.0 do bundle exec pumactl -S /home/deploy/myapp/shared/tmp/pids/puma.state -F /home/deploy/myapp/s…
      01 Command restart sent success

However, when I visit my website, I see:

502 Bad Gateway
nginx/1.4.6 (Ubuntu)

Doing cap production puma:status warns me that Puma is not running. Interestingly, cap production puma:start works perfectly with the following echo:

puma:start
      using conf file /home/deploy/myapp/shared/puma.rb
      01 ~/.rvm/bin/rvm ruby-2.4.0 do bundle exec puma -C /home/deploy/myapp/shared/puma.rb --daemon
      01 Puma starting in single mode...
      01
      01 * Version 3.9.1 (ruby 2.4.0-p0), codename: Private Caller
      01
      01 * Min threads: 0, max threads: 8
      01
      01 * Environment: production
      01
      01 * Daemonizing...
      01

I have spent a few hours trying to find out what the issue is. I can work around the issue by doing starting the Puma server everytime I deploy instead of the restart or phased_restart tasks. But what could be causing this? I deployed a similar app 2 weeks back (it was an API only app) and it worked without any issues.

Here is my deploy.rb:

lock "3.8.2"

set :application, "myapp"
set :repo_url, "[email protected]:myorg/myapp.git"

# set :branch, :master
set :branch, :release
set :deploy_to, '/home/deploy/myapp'
set :pty, true
set :linked_files, %w{config/database.yml config/application.yml}
# set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/uploads}
set :linked_dirs, %w{log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/uploads}

set :keep_releases, 5
set :rvm_type, :user
set :rvm_ruby_version, 'ruby-2.4.0'

set :puma_rackup, -> { File.join(current_path, 'config.ru') }
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/puma.sock"
set :puma_conf, "#{shared_path}/puma.rb"
set :puma_access_log, "#{shared_path}/log/puma_error.log"
set :puma_error_log, "#{shared_path}/log/puma_access.log"
set :puma_role, :app
set :puma_env, fetch(:rack_env, fetch(:rails_env, 'production'))
set :puma_threads, [0, 8]
set :puma_workers, 0
set :puma_worker_timeout, nil
set :puma_init_active_record, true
set :puma_preload_app, false

My config/deploy/production.rb:

server 'myapp.com', user: 'deploy', roles: %w{web app db}

My puma.rb:

#!/usr/bin/env puma

directory '/home/deploy/myapp/current'
rackup "/home/deploy/myapp/current/config.ru"
environment 'production'
daemonize true

tag ''

pidfile "/home/deploy/myapp/shared/tmp/pids/puma.pid"
state_path "/home/deploy/myapp/shared/tmp/pids/puma.state"
stdout_redirect '/home/deploy/myapp/shared/log/puma_error.log', '/home/deploy/myapp/shared/log/puma_access.log', true

threads 0,8

bind 'unix:///home/deploy/myapp/shared/tmp/sockets/puma.sock'

workers 0
prune_bundler

on_restart do
  puts 'Refreshing Gemfile'
  ENV["BUNDLE_GEMFILE"] = "/home/deploy/myapp/current/Gemfile"
end

I am really stuck here. Even after hours of research, I cannot find a solution that works!


Solution

  • As pointed out in the comments by Matt, this seems to be a reported bug. I have monkey patched the puma:restart task as a temporary solution until this gets fixed.

    I have created /lib/capistrano/tasks/overwrite_restart.rake:

    namespace :puma do
      Rake::Task[:restart].clear_actions
    
      desc "Overwritten puma:restart task"
      task :restart do
        puts "Overwriting puma:restart to ensure that puma is running. Effectively, we are just starting Puma."
        puts "A solution to this should be found."
        invoke 'puma:stop'
        invoke 'puma:start'
      end
    end
    

    As an alternative, I guess we could overwrite the :register_hooks method in the capistrano-puma gem, and replace puma:restart with puma:stop and puma:start.