Rails app keeps crashing when experiencing heavy load - ruby-on-rails

I was testing my app as I am anticipating a heavy load next week. I am currently using BlazeMeter to simulate the load. My server is hosted on AWS Elasticbeanstalk and RDS using m5.large EC2 instance. I have set up my application using Puma, Capistrano and Nginx. My config are as below:
//nginx.conf
upstream app {
server unix: ///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}
server {
listen 80;
server_name example.com;
root / home / deploy / apps / appname / current / public;
if ($http_x_forwarded_proto != "https") {
return 301 https: //$server_name$request_uri;
}
}
server {
listen 443 default_server http2;
root / home / deploy / apps / appname / current / public;
try_files / system / maintenance.html $uri / index.html $uri $uri.html #app;
access_log /
var / log / nginx / access.log main;
access_log /
var / log / nginx / healthd / application.log.$year - $month - $day - $hour healthd;
error_log /
var / log / nginx / error.log debug;
location / assets {
alias /
var / app / current / public / assets;
gzip_static on;
gzip on;
expires max;
add_header Cache - Control public;
}
location~ * \.(jpg | jpeg | gif | css | png | js | ico | svg | svgz) $ {
gzip_static on;
gzip on;
expires max;
add_header Cache - Control public;
}
location #app {
proxy_pass http: //app; # match the name of upstream directive which is defined above
proxy_set_header Host $http_host;
proxy_set_header X - Real - IP $remote_addr;
proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for;
proxy_set_header X - Forwarded - Proto $scheme;
proxy_set_header HTTP_CLIENT_IP $remote_addr;
}
error_page 500 502 503 504 / 500. html;
location / 500. html {}
error_page 404 / 404. html;
location / 404. html {}
error_page 422 / 422. html;
location / 422. html {}
}
##config/deploy.rb
# config valid only for current version of Capistrano
lock "3.8.2"
set :application, "appname"
set :repo_url, #"censored"
set :user, 'deploy'
set :puma_threads, [16, 64]
set :puma_workers, 2
set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"#{}"/var/app/current"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true # Change to false when not using ActiveRecord
append :linked_files, %w{config/database.yml}
append :linked_dirs, ".bundle", "tmp", "public/system"#, %w{bin log tmp/pids tmp/cache tmp/store vendor/bundle public/system}
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'deploy:restart', 'puma:start'
invoke 'deploy'
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke 'puma:restart'
end
end
before :starting, :check_revision
after :finishing, :compile_assets
end
There are many tests which failed and the error percentage is high. According to my logs from elasticbeanstalk,
[error] 2465#0: *2262 testing "/var/app/current/public/assets" existence failed (2: No such file or directory)
[crit] 2465#0: *2216 connect() to unix:///var/run/puma/my_app.sock failed (2: No such file or directory) while connecting to upstream
I am a newbie to this and I have no idea why this is happening! Any help is appreciated! Thanks!
Update 1: My website also shows 502 Bad Gateway Nginx after reaching a certain number of users simulated.
Update 2:
Like what Myst has pointed out, I am using a database as well.
default: &default
adapter: sqlite3
pool: 5
timeout: 5000
development:
<<: *default
database: db/development.sqlite3
test:
<<: *default
adapter: mysql2
encoding: utf8
database: <%= ENV['RDS_DB_NAME'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOSTNAME'] %>
port: <%= ENV['RDS_PORT'] %>
production:
<<: *default
adapter: mysql2
encoding: utf8
database: <%= ENV['RDS_DB_NAME'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOSTNAME'] %>
port: <%= ENV['RDS_PORT'] %>
pool: 50 #20
timeout: 10000
Versions:
capistrano3-puma (3.1.0)
ruby (2.3.0)
rails (4.2.8)
mysql2 (0.4.9)

In general - when dealing with high load at first it's good to measure machine metrics - how much load can it take in terms of RPS/simultaneous clients while being stable. And during this test - LA, memory usage, IO to determine what resource is current bottleneck.
Set upstream connections limit in nginx (server unix:///... max_conns=20;), it is unlimited by default and under stress test this may cause workers to swell and get Out-of-memory errors.
Once workers are dead - nginx cannot connect to socket and reports error 502.
See if your puma_error_log (it looks that it is confused with access log in config) has exceptions.
Also since you only have 2 cpu cores - I doubt there's need for 64 threads times 2 workers, unless most of your requests result in waiting for calls to an external api.

Related

Capistrano + puma + nginx: Capistrano puma is not creating puma-sockets and puma ids

Puma sockets and pids are not created after deploying with Capistrano. I have rails 5.1.2 application with ruby 2.4.0. Getting following error:
unix:///home/deploy/affiliate-staging/shared/tmp/sockets/affiliate-staging-puma.sock failed (2: No such file or directory) while connecting to upstream, client: client_id
cap staging deploy:initial successfully completes. Have googled it and followed many links and answers but nothing is working. The deploy.rb and other files are following.
config/deploy.rb
# config valid for current version and patch releases of Capistrano
lock "~> 3.11.0"
# Change these
server 'my_iP-address', roles: [:web, :app, :db], primary: true
set :repo_url, 'git#github.com'
set :user, 'deploy'
set :puma_threads, [4, 16]
set :puma_workers, 0
# Don't change these unless you know what you're doing
set :pty, true
set :use_sudo, false
set :deploy_via, :remote_cache
set :deploy_to, "/home/deploy/#{fetch(:application)}"
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/#{fetch(:application)}-puma.sock"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :ssh_options, { forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub) }
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true # Change to false when not using ActiveRecord
## Defaults:
# set :scm, :git
# set :branch, :master
# set :format, :pretty
# set :log_level, :debug
set :keep_releases, 5
## Linked Files & Directories (Default None):
set :bundle_binstubs, nil
append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', '.bundle', 'public/system', 'public/uploads'
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
if fetch(:stage) == (:staging || 'staging')
if `git rev-parse HEAD` != `git rev-parse origin/staging`
puts "WARNING: HEAD is not the same as origin/staging"
puts "Run `git push` to sync changes."
exit
end
elsif `git rev-parse HEAD` != `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'deploy:restart', 'puma:start'
invoke 'deploy'
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke!('puma:restart')
end
end
before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :cleanup
after :finishing, :restart
end
Setting up branch, application, and stage in config/deploy/staging.rb
set :application, 'affiliate-staging'
set :deploy_to, "/home/deploy/#{fetch(:application)}"
set :stage, :staging
set :rails_env, :staging
set :branch, :staging
config/nginx.conf
upstream puma {
#using same puma socket name which I am sertting up in staging.rb
server unix:///home/deploy/affiliate-staging/shared/tmp/sockets/affiliate-staging-puma.sock;
}
server {
listen 80 default_server deferred;
# server_name example.com;
root /home/deploy/affiliate-staging/current/public;
access_log /home/deploy/affiliate-staging/current/log/nginx.access.log;
error_log /home/deploy/affiliate-staging/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 100M;
keepalive_timeout 10;
}
As you can see there should be pids and affiliate-saintlbeau-puma.sock but its not created. I am getting this error:
unix:///home/deploy/affiliate-staging/shared/tmp/sockets/affiliate-staging-puma.sock failed (2: No such file or directory) while connecting to upstream, client: client_id
shared/puma.rb
#!/usr/bin/env puma
directory '/home/deploy/affiliate-staging/current'
rackup "/home/deploy/affiliate-staging/current/config.ru"
environment 'staging'
tag ''
pidfile "/home/deploy/shared/tmp/pids/puma.pid"
state_path "/home/deploy/shared/tmp/pids/puma.state"
stdout_redirect '/home/deploy/current/log/puma.error.log', '/home/deploy/current/log/puma.access.log', true
threads 4,16
bind 'unix:///home/deploy/shared/tmp/sockets/puma.sock'
workers 0
preload_app!
on_restart do
puts 'Refreshing Gemfile'
ENV["BUNDLE_GEMFILE"] = ""
end
before_fork do
ActiveRecord::Base.connection_pool.disconnect!
end
on_worker_boot do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.establish_connection
end
end
I am unable to understand what I am missing here. I hope I haven't messed up the question.

Puma not creating socket file while deployed with Capistrano

I have followed the tutorial here on ow to deploy a Rails App using Capistrano and Puma. I had initially used with a Rails 4 and all worked fine, however I'm now trying with Rails 5 App and is not working. I've made some changes due to changes in Capistrano (I've also upgraded Capistrano) and now I'm stuck as the deployment does not seem to create the sock file while deploying and I get the following error:
*412 connect() to unix:///var/www/apps/myapp/shared/tmp/sockets/myapp-puma.sock failed (2: No such file or directory) while connecting to upstream, client: 172.245.92.157, server: api.myapp.com, request: "GET / HTTP/1.0", upstream: "http://unix:///var/www/apps/myapp/shared/tmp/sockets/myapp-puma.sock:/", host: "roboarticle.com"
Here's my Capfile:
# Load DSL and set up stages
require 'capistrano/setup'
require 'capistrano/deploy'
# Include default deployment tasks
# require 'capistrano/rails'
require 'capistrano/bundler'
require 'capistrano/rvm'
require 'capistrano/puma'
install_plugin Capistrano::Puma
require 'capistrano/secrets_yml'
require 'capistrano/sidekiq'
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
Here's my deploy.rb:
# config valid only for current version of Capistrano
lock '3.8.0'
set :application, 'myapp'
# set :repo_url, 'git#example.com:me/my_repo.git'
# Change these
# server '178.62.117.38', roles: [:web, :app, :db], primary: true
set :repo_url, 'git#gitlab.com:WagnerMatos/myapp.git'
set :application, 'myapp'
set :user, 'deployer'
set :puma_threads, [4, 16]
set :puma_workers, 0
# Don't change these unless you know what you're doing
set :pty, false
set :use_sudo, false
set :deploy_to, "/var/www/apps/#{fetch(:application)}"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, false # Change to false when not using ActiveRecord
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system public/uploads}
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc "Make sure local git is in sync with remote."
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/staging`
puts "WARNING: HEAD is not the same as origin/staging"
puts "Run `git push` to sync changes."
exit
end
end
end
desc "reload the database with seed data"
task :seed do
puts "\n=== Seeding Database ===\n"
on primary :db do
within current_path do
with rails_env: fetch(:stage) do
execute :rake, 'db:seed'
end
end
end
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'deploy:restart', 'puma:start'
invoke 'deploy'
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke 'puma:restart'
# execute :bundle, 'exec cap production setup'
end
end
after 'deploy:starting', 'sidekiq:quiet'
after 'deploy:reverted', 'sidekiq:restart'
after 'deploy:published', 'sidekiq:restart'
# before :starting, :check_revision
# after :finishing, :compile_assets
after :finishing, :cleanup
after :finishing, :restart
# after("deploy:compile_assets", "deploy:build_missing_paperclip_styles")
end
# ps aux | grep puma # Get puma pid
# kill -s SIGUSR2 pid # Restart puma
# kill -s SIGTERM pid # Stop puma
And here's my nguni config file:
upstream puma {
server unix:///var/www/apps/myapp/shared/tmp/sockets/myapp-puma.sock;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}
server {
listen 443 default_server deferred;
server_name api.myapp.io;
ssl on;
ssl_certificate /etc/nginx/ssl/api.myapp.io/ssl-bundle.crt;
ssl_certificate_key /etc/nginx/ssl/api.myapp.io/api.myapp.io.key;
ssl_prefer_server_ciphers on;
root /var/www/apps/myapp/current/public;
access_log /var/www/apps/myapp/current/log/nginx.access.log;
error_log /var/www/apps/myapp/current/log/nginx.error.log info;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
proxy_read_timeout 300;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4000M;
keepalive_timeout 10;
}
Any ideas of what I'm missing here?

Nginx rendering 502 error page

I'm trying to configure nginx with puma to server my Ruby on Rails application. Whenever I visit my page I get a 502 bad gateway error.
/etc/nginx/sites-enabled/puma-api
upstream puma_puma-api_production {
server unix:/home/deploy/apps/puma-api/shared/tmp/sockets/puma-api-puma.sock fail_timeout=0;
}
server {
listen 80 default;
client_max_body_size 4G;
keepalive_timeout 10;
error_page 500 502 504 /500.html;
error_page 503 #503;
root /home/deploy/apps/puma-api/current/public;
try_files $uri/index.html $uri #puma_puma-api_production;
location #puma_puma-api_production {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma_puma-api_production;
# limit_req zone=one;
access_log /home/deploy/apps/puma-api/shared/log/nginx.access.log;
error_log /home/deploy/apps/puma-api/shared/log/nginx.error.log;
}
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location = /50x.html {
root html;
}
location = /404.html {
root html;
}
location #503 {
error_page 405 = /system/maintenance.html;
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html break;
}
rewrite ^(.*)$ /503.html break;
}
if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
return 405;
}
if (-f $document_root/system/maintenance.html) {
return 503;
}
location ~ \.(php|html)$ {
return 405;
}
}
/etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_requests 100;
keepalive_timeout 65;
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_vary off;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/rss+xml application/atom+xml text/javascript application/javascript application/json text/mathml;
gzip_min_length 1000;
gzip_disable "MSIE [1-6]\.";
variables_hash_max_size 1024;
variables_hash_bucket_size 64;
server_names_hash_bucket_size 64;
types_hash_max_size 2048;
types_hash_bucket_size 64;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
app/config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count
preload_app!
rackup DefaultRackup
port ENV['PORT'] || 5000
environment ENV['RACK_ENV'] || 'development'
on_worker_boot do
# Worker specific setup for Rails 4.1+
# See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
ActiveRecord::Base.establish_connection
end
deploy.rb
# config valid only for current version of Capistrano
lock '3.4.0'
set :application, 'puma-api'
set :repo_url, 'git#github.com:chaione/puma-api.git'
set :user, 'deploy'
# set :nginx_domains, 'localhost'
# set :app_server_socket, "#{shared_path}/sockets/puma-#{fetch :application}.sock"
# Default branch is :master
ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp
# Default deploy_to directory is /var/www/my_app_name
# set :deploy_to, '/var/www/my_app_name'
set :puma_threads, [4, 16]
set :puma_workers, 0
# Don't change these unless you know what you're doing
set :pty, true
set :use_sudo, false
set :stage, :production
set :deploy_via, :remote_cache
set :deploy_to, "/home/#{fetch(:user)}/apps/#{fetch(:application)}"
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state, "#{shared_path}/tmp/pids/puma.state"
set :puma_pid, "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{release_path}/log/puma.error.log"
set :puma_error_log, "#{release_path}/log/puma.access.log"
set :ssh_options, forward_agent: true, user: fetch(:user), keys: %w(~/.ssh/id_rsa.pub)
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true
namespace :puma do
desc 'Create Directories for Puma Pids and Socket'
task :make_dirs do
on roles(:app) do
execute "mkdir #{shared_path}/tmp/sockets -p"
execute "mkdir #{shared_path}/tmp/pids -p"
end
end
before :start, :make_dirs
end
namespace :deploy do
desc 'Make sure local git is in sync with remote.'
task :check_revision do
on roles(:app) do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts 'WARNING: HEAD is not the same as origin/master'
puts 'Run `git push` to sync changes.'
exit
end
end
end
desc 'Initial Deploy'
task :initial do
on roles(:app) do
before 'deploy:restart', 'puma:start'
invoke 'deploy'
end
end
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke 'puma:restart'
end
end
# before :starting, :check_revision
after :finishing, :compile_assets
after :finishing, :cleanup
after :finishing, :restart
end
# # Default value for :linked_files is []
# set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/images')
# set :linked_files, fetch(:linked_files, []).push('config/database.yml', 'config/secrets.yml')
# Default value for default_env is {}
# set :default_env, { path: "/opt/ruby/bin:$PATH" }
namespace :deploy do
after :restart, :clear_cache do
on roles(:web), in: :groups, limit: 3, wait: 10 do
# Here we can do anything such as:
# within release_path do
# execute :rake, 'cache:clear'
# end
end
end
end
app recipe
# create www directory
directory '/var/www' do
user node['user']['name']
group node['group']
mode 0755
end
# create shared directory structure for app
path = "/var/www/#{node['app']}/shared/config"
execute "mkdir -p #{path}" do
user node['user']['name']
group node['group']
creates path
end
# create database.yml file
template "#{path}/database.yml" do
source 'database.yml.erb'
mode 0640
owner node['user']['name']
group node['group']
end
You have nginx communicating with your puma server via socket
/home/deploy/apps/puma-api/shared/tmp/sockets/puma-api-puma.sock
You have puma creating this socket at
set :puma_bind, "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
I can't see shared_path defined anywhere in your code though. Make sure that these two match (or just hardcode the path to eliminate variables for now).
I would also first check if /home/deploy/apps/puma-api/shared/tmp/sockets/puma-api-puma.sock even exists.

Why is Capistrano deploying my project in "development" environment?

I have the following files set up for my capistrano configuration. When I deploy my project with the following command it deploys to the server, but the Rails.env is set to 'deployment'. How can I have it properly set to 'production'?
deploy command
cap production deploy
deploy.rb
set :application, 'project'
set :repo_url, 'git#github.com:AccountName/project.git'
set :deploy_to, '/home/deploy/project'
set :linked_files, %w{config/database.yml}
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}
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')
end
end
after :publishing, 'deploy:restart'
after :finishing, 'deploy:cleanup'
end
config/deploy/production.rb
set :stage, :production
set :branch, 'master'
set :rails_env, 'production'
server '127.0.0.1:4400', user: 'deploy', roles: %w{web app}
nginx.conf
server {
listen 80;
server_name ip_address;
rails_env production;
root /path/to/app/public;
passenger_enabled on;
}
sites-available/project
server {
listen 80 default_server;
server_name ip_address;
passenger_enabled on;
root /path/to/app/public;
}
The problem was that the passenger_app_env was at development. I couldn't figure out which services weren't restarted so I did a reboot of the server. Which presented some other issues, but I'm fairly certain the problem was resolved by changing that variable to passenger_app_env production. Thanks for the help!

Rails project: routes give 500 errors in production but work in development

I'm having some trouble getting my rails app to run in production. As I've coded rails before but haven't deployed much it's probably something in my configs and/or deployment process.
Everything runs fine locally in development. All tests pass, I can see the routes and access them at localhost. When in production (rails 4, nginx, unicorn on CentOS) I'm getting 500 errors on the very same routes.
When I rake routes on the server I see all the same routes as when in development. Rake routes on the server returns (shortened from the full list of routes):
Prefix Verb URI Pattern Controller#Action
companies GET /companies(.:format) companies#index
POST /companies(.:format) companies#create
new_company GET /companies/new(.:format) companies#new
edit_company GET /companies/:id/edit(.:format) companies#edit
company GET /companies/:id(.:format) companies#show
PATCH /companies/:id(.:format) companies#update
PUT /companies/:id(.:format) companies#update
DELETE /companies/:id(.:format) companies#destroy
Which as you can probably guess comes from resources :companies
But http://sortinghat.foo.com/companies gives me the rails 500 page on production (foo is obviously not the domain but I've just replaced the real domain).
I am at a loss having searched on here and the web for ideas, having read lots of "how to deploy rails" blog posts, and have looked at lots of config files (you'll see these are ones I copied from elsewhere but it all seems pretty standard). I'm probably missing something obvious. I'm not seeing any issues in the logs.
The only clue I have is that I don't have an /etc/nginx/sites-enabled directory and it looks like capistrano wants one, but I didn't see any errors during cap deploy (except the cleanup one I note at the bottom). In this case it's the only site being run so I don't need a virtual host and didn't think I needed it so wasn't concerned.
Thanks in advance for any help.
Here's my nginx.config
# Taken from http://www.sitepoint.com/deploying-your-rails-app-to-the-cloud-with-unicorn-nginx-and-capistrano/
upstream unicorn {
server unix:/tmp/unicorn.sortinghat.sock fail_timeout=0;
}
server {
listen 80 default deferred;
server_name sortinghat;
if ($host = 'sortinghat' ) {
rewrite ^/(.*)$ http://sortinghat.foo.com/$1 permanent;
}
root /var/www/sortinghat/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
My unicorn.rb
# Taken from http://www.sitepoint.com/deploying-your-rails-app-to-the-cloud-with-unicorn-nginx-and-capistrano/
# Define your root directory
root = "/var/www/sortinghat/current"
# Define worker directory for Unicorn
working_directory root
# Location of PID file
pid "#{root}/tmp/pids/unicorn.pid"
# Define Log paths
stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"
# Listen on a UNIX data socket
listen "/tmp/unicorn.sortinghat.sock"
# 16 worker processes for production environment
worker_processes 16
# Load rails before forking workers for better worker spawn time
preload_app true
# Restart workes hangin' out for more than 240 secs
timeout 240
And my deploy.rb (Note: I made some things world readable with the chmod 777 as a quick hack. I'm just trying to get this running internally to run a test all behind a firewall. I can probably take those out but I doubt they're hurting anything right now.)
require 'capistrano/ext/multistage'
set :application, "sortinghat"
# Need to use gnutar since that is what the server uses
# see https://coderwall.com/p/ypwmpg
set :copy_local_tar, "/usr/bin/gnutar" if `uname` =~ /Darwin/
# remove old releases
set :keep_releases, 3
# Source Control
# You can set :scm explicitly or Capistrano will make an intelligent guess based on known version control directory names
# Or: `accurev`, `bzr`, `cvs`, `darcs`, `git`, `mercurial`, `perforce`, `subversion` or `none`
set :repository, "git#github.com:me/project.git" # changed here but correct in the actual file
set :scm, :git
set :branch, "master"
set :deploy_via, :copy
# Deployment
# Default deployment directory is /u/apps/#{application}” (where #{application} but alternate can be set
# set :deploy_to, "/var/www"
set :user, "mherschberg"
default_run_options[:pty] = true
set :use_sudo, false
set :ssh_options, {:forward_agent => true}
role :web, "sortinghat.foo.com" # Your HTTP server, Apache/etc
role :app, "sortinghat.foo.com" # This may be the same as your `Web` server
role :db, "lin-db3.foo.com", :primary => true #, :no_release => true # This is where Rails migrations will run
#role :db, "your slave db-server here" # no slave for test
set :rails_env, "production"
set :stages, ["staging", "production"]
set :default_stage, "staging"
# if you want to clean up old releases on each deploy uncomment this:
after "deploy:restart", "deploy:cleanup"
namespace :deploy do
%w[start stop restart].each do |command|
desc "#{command} unicorn server"
task command, roles: :app, except: {no_release: true} do
sudo "chmod 777 /var/www/sortinghat/current/config/unicorn_ini.sh"
run "/etc/init.d/unicorn_#{application} #{command}" # Using unicorn as the app server
end
end
task :setup_config, roles: :app do
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
sudo "ln -nfs #{current_path}/config/unicorn_ini.sh /etc/init.d/unicorn_#{application}"
sudo "chmod 777 #{current_path}/config/unicorn_ini.sh"
sudo "chmod 777 /var/www/sortinghat/current/config/unicorn_ini.sh"
run "mkdir -p #{shared_path}/config"
put File.read("config/database.yml"), "#{shared_path}/config/database.yml"
puts "Now edit the config files in #{shared_path}."
end
after "deploy:setup", "deploy:setup_config"
task :symlink_config, roles: :app do
run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
end
after "deploy:finalize_update", "deploy:symlink_config"
desc "Make sure local git is in sync with remote."
task :check_revision, roles: :web do
unless `git rev-parse HEAD` == `git rev-parse origin/master`
puts "WARNING: HEAD is not the same as origin/master"
puts "Run `git push` to sync changes."
exit
end
end
before "deploy", "deploy:check_revision"
end
# if you're still using the script/reaper helper you will need
# these http://github.com/rails/irs_process_scripts
# If you are using Passenger mod_rails uncomment this:
# namespace :deploy do
# task :start do ; end
# task :stop do ; end
# task :restart, :roles => :app, :except => { :no_release => true } do
# run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
# end
# end
cap deploy works with only one error, but it's just a problem with permissions cleaning up old releases. ( cap deploy:cold ran fine)
** [out :: sortinghat.foo.com] rm: cannot remove `/var/www/sortinghat/releases/20130917180205/thout-curl-include=dir/include/build_info': Permission denied
The answer from a friend was: use passenger, not unicorn. It pretty much worked out of the box.
You can find it at https://www.phusionpassenger.com/
(I did have some strange issue which I got error 128 from github. Nothing had changed in my deploy.rb except to uncomment the commented out lined at the bottom for passenger; certainly nothing changed in my github account or AFAIK locally. I'm not sure what happened but I deleted my github key for this machine, created a new one and then everything worked.)

Resources