Search code examples
ruby-on-railsunicornrbenvcapistrano3

Deploy rails app with capistrano rbenv unicorn


I have problem staring unicorn during deploy. The stack trace is the same as if I execute from "app_name"/current directory:

bundle exec rails c production

deployer@cloud-number-nine:~/qna/current$ bundle exec rails c production
[DEPRECATION] the dotenv-deployment gem is deprecated. See https://github.com/bkeepers/dotenv-deployment#readme.
/home/deployer/qna/releases/20160521190207/app/serializers/votable_serializer.rb:5:in `<class:VotableSerializer>': undefined method `root=' for VotableSerializer:Class (NoMethodError)
    from /home/deployer/qna/releases/20160521190207/app/serializers/votable_serializer.rb:2:in `<top (required)>'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `require'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `block in require'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `require'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:360:in `require_or_load'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:317:in `depend_on'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:233:in `require_dependency'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/engine.rb:472:in `block (2 levels) in eager_load!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/engine.rb:471:in `each'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/engine.rb:471:in `block in eager_load!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/engine.rb:469:in `each'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/engine.rb:469:in `eager_load!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/engine.rb:346:in `eager_load!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/application/finisher.rb:56:in `each'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/application/finisher.rb:56:in `block in <module:Finisher>'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/initializable.rb:30:in `instance_exec'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/initializable.rb:30:in `run'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/initializable.rb:55:in `block in run_initializers'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:228:in `block in tsort_each'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:431:in `each_strongly_connected_component_from'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:349:in `block in each_strongly_connected_component'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:347:in `each'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:347:in `call'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:347:in `each_strongly_connected_component'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:226:in `tsort_each'
    from /home/deployer/.rbenv/versions/2.3.0/lib/ruby/2.3.0/tsort.rb:205:in `tsort_each'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/initializable.rb:54:in `run_initializers'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/application.rb:352:in `initialize!'
    from /home/deployer/qna/releases/20160521190207/config/environment.rb:5:in `<top (required)>'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `require'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `block in require'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:240:in `load_dependency'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/activesupport-4.2.5/lib/active_support/dependencies.rb:274:in `require'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/application.rb:328:in `require_environment!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:142:in `require_application_and_environment!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:67:in `console'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /home/deployer/qna/shared/bundle/ruby/2.3.0/gems/railties-4.2.5/lib/rails/commands.rb:17:in `<top (required)>'
    from bin/rails:9:in `require'
    from bin/rails:9:in `<main>'

Capfile:

# Load DSL and set up stages
require 'capistrano/setup'

# Include default deployment tasks
require 'capistrano/deploy'
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails'
require 'capistrano/sidekiq'
require 'capistrano3/unicorn'
require 'whenever/capistrano'
require 'thinking_sphinx/capistrano'

Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }

deploy.rb

# config valid only for current version of Capistrano
lock '3.5.0'

set :application, 'qna'
set :repo_url, 'git@github.com:khataev/qna.git'

# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, '/home/deployer/qna'
set :deploy_user, 'deployer'

# Default value for :linked_files is []
set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/private_pub.yml', 'config/private_pub_thin.yml', '.env')

# Default value for linked_dirs is []
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system', 'vendor/bundle', 'public/uploads')

# rbenv
set :rbenv_type, :user # or :system, depends on your rbenv setup
set :rbenv_ruby, '2.3.0'

set :rbenv_prefix, "RBENV_ROOT=#{fetch(:rbenv_path)} RBENV_VERSION=#{fetch(:rbenv_ruby)} #{fetch(:rbenv_path)}/bin/rbenv exec"
# set :rbenv_map_bins, %w(rake gem bundle ruby rails)
set :rbenv_roles, :all # default value
set :bundle_binstubs, nil

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # execute :touch, release_path.join('tmp/restart.txt')
      invoke 'unicorn:restart'
    end
  end

  after :publishing, :restart
end

namespace :private_pub do
  desc 'Start private_pub server'
  task :start do
    on roles(:app) do
      within current_path do
        with rails_env: fetch(:rails_env) do
          execute :bundle, 'exec thin -C config/private_pub_thin.yml start'
        end
      end
    end
  end

  desc 'Stop private_pub server'
  task :stop do
    on roles(:app) do
      within current_path do
        with rails_env: fetch(:rails_env) do
          execute :bundle, 'exec thin -C config/private_pub_thin.yml stop'
        end
      end
    end
  end

  desc 'Restart private_pub server'
  task :restart do
    on roles(:app) do
      within current_path do
        with rails_env: fetch(:rails_env) do
          execute :bundle, 'exec thin -C config/private_pub_thin.yml restart'
        end
      end
    end
  end
end

after 'deploy:restart', 'private_pub:restart'
after 'deploy:restart', 'thinking_sphinx:restart'

unicorn/production.rb

# paths
app_path = '/home/deployer/qna'
working_directory "#{app_path}/current"
pid               "#{app_path}/current/tmp/pids/unicorn.pid"

# listen
listen '/tmp/unicorn.qna.sock', backlog: 64

# logging
stderr_path 'log/unicorn.stderr.log'
stdout_path 'log/unicorn.stdout.log'

# workers
worker_processes 2

# use correct Gemfile on restarts
before_exec do |_server|
  ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile"
end

# preload
preload_app true

before_fork do |server, _worker|
  # the following is highly recomended for Rails + "preload_app true"
  # as there's no need for the master process to hold a connection
  ActiveRecord::Base.connection.disconnect! if defined?(ActiveRecord::Base)

  # Before forking, kill the master process that belongs to the .oldbin PID.
  # This enables 0 downtime deploys.
  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exist?(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|
  ActiveRecord::Base.establish_connection if defined?(ActiveRecord::Base)
end

votable serializer

My opinion that problem lies between rbenv and unicorn, but I'm not shure...


Solution

  • I believe that your problem is actually not related to unicorn. In a comment above you said that "it didn't cause problems in production until I wanted to migrate from passenger to unicorn". But, the commit to switch to unicorn reveals that during this step the active_model_serializers gem has been upgraded from version 0.9.5 to 0.10.0.

    This turns out to be significant for your serializer as it seems that the self.root= method can no longer be used in the class context - it is now a normal attr_accessor in the ActiveModel::Serializer class, i.e. if at all, then it should be used in the instance context. See the old version vs the new version.

    Anyway, if you wanted to just NOT include the root when serializing the object, you should just be able to switch to the - now default - AttributesAdapter. You may use the adapter: :attributes when rendering the objects in your controller.