Commit 4964372e7ca61b592d5d28f33aec4bc6b3ea57b0

Authored by Stephen Crosby
2 parents 8c105794 78538cf6
Exists in master

Merge pull request #1005 from otzy007/puma

Use puma instead of unicorn
@@ -23,8 +23,3 @@ GITHUB_API_URL=https://api.github.com @@ -23,8 +23,3 @@ GITHUB_API_URL=https://api.github.com
23 GITHUB_ACCESS_SCOPE='[repo]' 23 GITHUB_ACCESS_SCOPE='[repo]'
24 GITHUB_SITE_TITLE=GitHub 24 GITHUB_SITE_TITLE=GitHub
25 DEVISE_MODULES='[database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable]' 25 DEVISE_MODULES='[database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable]'
26 -USE_UNICORN_WORKER_KILLER=false  
27 -KILL_ON_REQUEST_COUNT_MIN=3072  
28 -KILL_ON_REQUEST_COUNT_MAX=4096  
29 -KILL_ON_RSS_MIN=250  
30 -KILL_ON_RSS_MAX=300  
@@ -4,5 +4,6 @@ require 'capistrano/deploy' @@ -4,5 +4,6 @@ require 'capistrano/deploy'
4 require 'capistrano/rbenv' if ENV['rbenv'] 4 require 'capistrano/rbenv' if ENV['rbenv']
5 require 'capistrano/bundler' 5 require 'capistrano/bundler'
6 require 'capistrano/rails/assets' 6 require 'capistrano/rails/assets'
  7 +require 'capistrano/puma'
7 8
8 Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } 9 Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
@@ -76,6 +76,7 @@ group :development do @@ -76,6 +76,7 @@ group :development do
76 gem 'capistrano-bundler', require: false 76 gem 'capistrano-bundler', require: false
77 gem 'capistrano-rails', require: false 77 gem 'capistrano-rails', require: false
78 gem 'capistrano-rbenv', require: false 78 gem 'capistrano-rbenv', require: false
  79 + gem 'capistrano3-puma', require: false
79 80
80 # better errors 81 # better errors
81 gem 'better_errors' 82 gem 'better_errors'
@@ -100,10 +101,9 @@ end @@ -100,10 +101,9 @@ end
100 101
101 group :heroku, :production do 102 group :heroku, :production do
102 gem 'rails_12factor', require: ENV.key?("HEROKU") 103 gem 'rails_12factor', require: ENV.key?("HEROKU")
103 - gem 'unicorn', require: false, platform: 'ruby'  
104 - gem 'unicorn-worker-killer'  
105 end 104 end
106 105
  106 +gem 'puma'
107 gem 'therubyracer', platform: :ruby # C Ruby (MRI) or Rubinius, but NOT Windows 107 gem 'therubyracer', platform: :ruby # C Ruby (MRI) or Rubinius, but NOT Windows
108 gem 'sass-rails' 108 gem 'sass-rails'
109 gem 'uglifier' 109 gem 'uglifier'
@@ -76,6 +76,9 @@ GEM @@ -76,6 +76,9 @@ GEM
76 capistrano-rbenv (2.0.3) 76 capistrano-rbenv (2.0.3)
77 capistrano (~> 3.1) 77 capistrano (~> 3.1)
78 sshkit (~> 1.3) 78 sshkit (~> 1.3)
  79 + capistrano3-puma (1.2.1)
  80 + capistrano (~> 3.0)
  81 + puma (>= 2.6)
79 capybara (2.4.4) 82 capybara (2.4.4)
80 mime-types (>= 1.16) 83 mime-types (>= 1.16)
81 nokogiri (>= 1.3.3) 84 nokogiri (>= 1.3.3)
@@ -134,7 +137,6 @@ GEM @@ -134,7 +137,6 @@ GEM
134 multi_json 137 multi_json
135 font-awesome-rails (4.2.0.0) 138 font-awesome-rails (4.2.0.0)
136 railties (>= 3.2, < 5.0) 139 railties (>= 3.2, < 5.0)
137 - get_process_mem (0.2.0)  
138 globalid (0.3.6) 140 globalid (0.3.6)
139 activesupport (>= 4.1.0) 141 activesupport (>= 4.1.0)
140 haml (4.0.6) 142 haml (4.0.6)
@@ -165,7 +167,6 @@ GEM @@ -165,7 +167,6 @@ GEM
165 kaminari (0.16.3) 167 kaminari (0.16.3)
166 actionpack (>= 3.0.0) 168 actionpack (>= 3.0.0)
167 activesupport (>= 3.0.0) 169 activesupport (>= 3.0.0)
168 - kgio (2.9.3)  
169 launchy (2.4.3) 170 launchy (2.4.3)
170 addressable (~> 2.3) 171 addressable (~> 2.3)
171 launchy (2.4.3-java) 172 launchy (2.4.3-java)
@@ -258,6 +259,7 @@ GEM @@ -258,6 +259,7 @@ GEM
258 pry (~> 0.10) 259 pry (~> 0.10)
259 pry-rails (0.3.4) 260 pry-rails (0.3.4)
260 pry (>= 0.9.10) 261 pry (>= 0.9.10)
  262 + puma (2.15.3)
261 quiet_assets (1.1.0) 263 quiet_assets (1.1.0)
262 railties (>= 3.1, < 5.0) 264 railties (>= 3.1, < 5.0)
263 rack (1.6.4) 265 rack (1.6.4)
@@ -300,7 +302,6 @@ GEM @@ -300,7 +302,6 @@ GEM
300 rake (>= 0.8.7) 302 rake (>= 0.8.7)
301 thor (>= 0.18.1, < 2.0) 303 thor (>= 0.18.1, < 2.0)
302 rainbow (2.0.0) 304 rainbow (2.0.0)
303 - raindrops (0.13.0)  
304 rake (10.4.2) 305 rake (10.4.2)
305 ref (1.0.5) 306 ref (1.0.5)
306 request_store (1.1.0) 307 request_store (1.1.0)
@@ -398,13 +399,6 @@ GEM @@ -398,13 +399,6 @@ GEM
398 unf_ext 399 unf_ext
399 unf (0.1.4-java) 400 unf (0.1.4-java)
400 unf_ext (0.0.7.1) 401 unf_ext (0.0.7.1)
401 - unicorn (4.9.0)  
402 - kgio (~> 2.6)  
403 - rack  
404 - raindrops (~> 0.7)  
405 - unicorn-worker-killer (0.4.3)  
406 - get_process_mem (~> 0)  
407 - unicorn (~> 4)  
408 useragent (0.14.0) 402 useragent (0.14.0)
409 warden (1.2.3) 403 warden (1.2.3)
410 rack (>= 1.0) 404 rack (>= 1.0)
@@ -434,6 +428,7 @@ DEPENDENCIES @@ -434,6 +428,7 @@ DEPENDENCIES
434 capistrano-bundler 428 capistrano-bundler
435 capistrano-rails 429 capistrano-rails
436 capistrano-rbenv 430 capistrano-rbenv
  431 + capistrano3-puma
437 capybara 432 capybara
438 coveralls 433 coveralls
439 decent_exposure 434 decent_exposure
@@ -465,6 +460,7 @@ DEPENDENCIES @@ -465,6 +460,7 @@ DEPENDENCIES
465 poltergeist 460 poltergeist
466 pry-byebug 461 pry-byebug
467 pry-rails 462 pry-rails
  463 + puma
468 quiet_assets 464 quiet_assets
469 rack-ssl 465 rack-ssl
470 rack-ssl-enforcer 466 rack-ssl-enforcer
@@ -483,8 +479,6 @@ DEPENDENCIES @@ -483,8 +479,6 @@ DEPENDENCIES
483 timecop 479 timecop
484 uglifier 480 uglifier
485 underscore-rails 481 underscore-rails
486 - unicorn  
487 - unicorn-worker-killer  
488 useragent 482 useragent
489 xmpp4r 483 xmpp4r
490 yajl-ruby 484 yajl-ruby
1 -web: bundle exec unicorn -c ./config/unicorn.default.rb 1 +web: bundle exec puma -C config/puma.default.rb
1 -if ENV['USE_UNICORN_WORKER_KILLER']  
2 - require 'unicorn/worker_killer'  
3 - max_request_min = ENV['KILL_ON_REQUEST_COUNT_MIN'].to_i || 3072  
4 - max_request_max = ENV['KILL_ON_REQUEST_COUNT_MAX'].to_i || 4096  
5 - use Unicorn::WorkerKiller::MaxRequests, max_request_min, max_request_max  
6 - oom_min = ((ENV['KILL_ON_RSS_MIN'].to_i || 250) * (1024**2))  
7 - oom_max = ((ENV['KILL_ON_RSS_MAX'].to_i || 300) * (1024**2))  
8 - use Unicorn::WorkerKiller::Oom, oom_min, oom_max  
9 -end  
10 -  
11 # This file is used by Rack-based servers to start the application. 1 # This file is used by Rack-based servers to start the application.
12 2
13 require ::File.expand_path('../config/environment', __FILE__) 3 require ::File.expand_path('../config/environment', __FILE__)
config/deploy.example.rb
@@ -21,7 +21,7 @@ set :ssh_options, forward_agent: true @@ -21,7 +21,7 @@ set :ssh_options, forward_agent: true
21 set :linked_files, fetch(:linked_files, []) + %w( 21 set :linked_files, fetch(:linked_files, []) + %w(
22 .env 22 .env
23 config/newrelic.yml 23 config/newrelic.yml
24 - config/unicorn.rb 24 + config/puma.rb
25 ) 25 )
26 26
27 set :linked_dirs, fetch(:linked_dirs, []) + %w( 27 set :linked_dirs, fetch(:linked_dirs, []) + %w(
@@ -45,13 +45,14 @@ namespace :errbit do @@ -45,13 +45,14 @@ namespace :errbit do
45 execute "touch #{shared_path}/.env" 45 execute "touch #{shared_path}/.env"
46 46
47 { 47 {
48 - 'config/newrelic.example.yml' => 'config/newrelic.yml',  
49 - 'config/unicorn.default.rb' => 'config/unicorn.rb' 48 + 'config/newrelic.example.yml' => 'config/newrelic.yml'
50 }.each do |src, target| 49 }.each do |src, target|
51 unless test("[ -f #{shared_path}/#{target} ]") 50 unless test("[ -f #{shared_path}/#{target} ]")
52 upload! src, "#{shared_path}/#{target}" 51 upload! src, "#{shared_path}/#{target}"
53 end 52 end
54 end 53 end
  54 +
  55 + invoke 'puma:config'
55 end 56 end
56 end 57 end
57 end 58 end
@@ -69,47 +70,5 @@ namespace :db do @@ -69,47 +70,5 @@ namespace :db do
69 end 70 end
70 end 71 end
71 72
72 -set :unicorn_pidfile, "#{fetch(:deploy_to)}/shared/tmp/pids/unicorn.pid"  
73 -set :unicorn_pid, "`cat #{fetch(:unicorn_pidfile)}`"  
74 -  
75 -namespace :unicorn do  
76 - desc 'Start unicorn'  
77 - task :start do  
78 - on roles(:app) do  
79 - within current_path do  
80 - if test " [ -s #{fetch(:unicorn_pidfile)} ] "  
81 - warn "Unicorn is already running."  
82 - else  
83 - with "UNICORN_PID" => fetch(:unicorn_pidfile) do  
84 - execute :bundle, :exec, :unicorn, "-D -c ./config/unicorn.rb"  
85 - end  
86 - end  
87 - end  
88 - end  
89 - end  
90 -  
91 - desc 'Reload unicorn'  
92 - task :reload do  
93 - on roles(:app) do  
94 - execute :kill, "-HUP", fetch(:unicorn_pid)  
95 - end  
96 - end  
97 -  
98 - desc 'Stop unicorn'  
99 - task :stop do  
100 - on roles(:app) do  
101 - if test " [ -s #{fetch(:unicorn_pidfile)} ] "  
102 - execute :kill, "-QUIT", fetch(:unicorn_pid)  
103 - else  
104 - warn "Unicorn is not running."  
105 - end  
106 - end  
107 - end  
108 -  
109 - desc 'Reexecute unicorn'  
110 - task :reexec do  
111 - on roles(:app) do  
112 - execute :kill, "-USR2", fetch(:unicorn_pid)  
113 - end  
114 - end  
115 -end 73 +set :puma_conf, "#{shared_path}/config/puma.rb"
  74 +set :puma_bind, 'tcp://0.0.0.0:8080'
config/puma.default.rb 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +# https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server
  2 +
  3 +workers Integer(ENV['WEB_CONCURRENCY'] || 2)
  4 +threads_count = Integer(ENV['MAX_THREADS'] || 5)
  5 +threads threads_count, threads_count
  6 +
  7 +preload_app!
  8 +
  9 +rackup DefaultRackup
  10 +port ENV['PORT'] || 8080
  11 +environment ENV['RACK_ENV'] || 'development'
  12 +
  13 +on_worker_boot do
  14 + # Worker specific setup for Rails 4.1+
  15 + # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  16 + ActiveSupport.on_load(:active_record) do
  17 + ActiveRecord::Base.establish_connection
  18 + end
  19 +end
config/unicorn.default.rb
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -# http://michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-with-the-new-celadon-cedar-stack/  
2 -  
3 -worker_processes 3 # amount of unicorn workers to spin up  
4 -timeout 30 # restarts workers that hang for 30 seconds  
5 -preload_app true  
6 -listen ENV['PORT'] || 8080  
7 -pid ENV['UNICORN_PID'] if ENV['UNICORN_PID']  
8 -  
9 -# Taken from github: https://github.com/blog/517-unicorn  
10 -# Though everyone uses pretty miuch the same code  
11 -before_fork do |server, _worker|  
12 - ##  
13 - # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and  
14 - # immediately start loading up a new version of itself (loaded with a new  
15 - # version of our app). When this new Unicorn is completely loaded  
16 - # it will begin spawning workers. The first worker spawned will check to  
17 - # see if an .oldbin pidfile exists. If so, this means we've just booted up  
18 - # a new Unicorn and need to tell the old one that it can now die. To do so  
19 - # we send it a QUIT.  
20 - #  
21 - # Using this method we get 0 downtime deploys.  
22 -  
23 - old_pid = "#{server.config[:pid]}.oldbin"  
24 - if File.exist?(old_pid) && server.pid != old_pid  
25 - begin  
26 - Process.kill("QUIT", File.read(old_pid).to_i)  
27 - rescue Errno::ENOENT, Errno::ESRCH  
28 - warn "Unicorn: master process already killed, no problem"  
29 - end  
30 - end  
31 -end  
docs/configuration.md
@@ -5,7 +5,7 @@ Errbit takes all of its configuration from environment variables. You can use @@ -5,7 +5,7 @@ Errbit takes all of its configuration from environment variables. You can use
5 to fill in any values that you can't or won't supply through the environment. 5 to fill in any values that you can't or won't supply through the environment.
6 6
7 In order of precedence Errbit uses: 7 In order of precedence Errbit uses:
8 -1. Environment variables (for example MY_VALUE=abc bundle exec unicorn) 8 +1. Environment variables (for example MY_VALUE=abc bundle exec puma)
9 2. Values provided in a .env file 9 2. Values provided in a .env file
10 3. Default values from .env.default 10 3. Default values from .env.default
11 11
@@ -100,10 +100,4 @@ In order of precedence Errbit uses: @@ -100,10 +100,4 @@ In order of precedence Errbit uses:
100 <dt>DEVISE_MODULES 100 <dt>DEVISE_MODULES
101 <dd>Devise modules to enable 101 <dd>Devise modules to enable
102 <dd>defaults to [database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable] 102 <dd>defaults to [database_authenticatable,recoverable,rememberable,trackable,validatable,omniauthable]
103 -<dt>USE_UNICORN_WORKER_KILLER</dt>  
104 -<dd>unicorn-worker-killer modules to enable</dd>  
105 -<dd>defaults to false</dd>  
106 -<dt>ERRBIT_LOG_LOCATION</dt>  
107 -<dd>Path to use to store the log. Specify <em>STDOUT</em> for stdout output, <em>Syslog::Logger</em> to send logs to syslog (uses local0 facility).  
108 -<dd>defaults to STDOUT  
109 </dl> 103 </dl>
docs/deployment/capistrano.md
@@ -43,7 +43,20 @@ Errbit comes with some capistrano tasks to manage running Errbit under @@ -43,7 +43,20 @@ Errbit comes with some capistrano tasks to manage running Errbit under
43 unicorn. 43 unicorn.
44 To start Errbit, you can run: 44 To start Errbit, you can run:
45 ```bash 45 ```bash
46 -bundle exec cap production unicorn:start 46 +bundle exec cap production puma:start
  47 +```
  48 +
  49 +## Status of Errbit
  50 +To check if the Errbit server is running you can run:
  51 +```bash
  52 +bundle exec cap production puma:status
  53 +```
  54 +
  55 +## Stopping Errbit
  56 +To stop Errbit run
  57 +
  58 +```bash
  59 +bundle exec cap production puma:stop
47 ``` 60 ```
48 61
49 Supervising and monitoring Errbit is beyond the scope of this 62 Supervising and monitoring Errbit is beyond the scope of this
@@ -63,3 +76,47 @@ rbenv=1 bundle exec cap production deploy @@ -63,3 +76,47 @@ rbenv=1 bundle exec cap production deploy
63 ## Schedule recurring tasks 76 ## Schedule recurring tasks
64 You may want to periodically clear resolved errors to free up space. 77 You may want to periodically clear resolved errors to free up space.
65 Schedule ```rake errbit:db:clear_resolved``` to run every day or so. 78 Schedule ```rake errbit:db:clear_resolved``` to run every day or so.
  79 +
  80 +
  81 +## Monit
  82 +If you like errbit to be monitored by monit, you'll have to install and start monit
  83 +with http support before deploying errbit.
  84 +In order to enable http support you have to edit the monit config file which you can
  85 +find in `/etc/monit/monitrc` for Ubuntu and set these lines:
  86 +```
  87 +set httpd port 2812 and
  88 + use address localhost # only accept connection from localhost
  89 + allow localhost
  90 +```
  91 +
  92 +Next you have to add the following line to the Capfile:
  93 +```
  94 +require 'capistrano/puma/monit'
  95 +```
  96 +
  97 +And you have to deploy the monit config with the command:
  98 +```bash
  99 +bundle exec cap production puma:monit:config
  100 +```
  101 +
  102 +The configuration file (depending on the distro) will be generated at: `/etc/monit/conf.d/puma_errbit_production.conf`
  103 +
  104 +### Controlling memory usage with monit
  105 +If you like to limit memory usage for puma and restart it in case the usage gets
  106 +over a 2GB limit, for example, you can add at the end of the monit config file the line
  107 +```
  108 +if totalmem is greater than 2048 MB for 3 cycles then restart
  109 +```
  110 +
  111 +The config file will look like:
  112 +
  113 +```
  114 +# Monit configuration for Puma
  115 +# Service name: puma_errbit_production
  116 +#
  117 +check process puma_errbit_production
  118 + with pidfile "/var/www/apps/errbit/shared/tmp/pids/puma.pid"
  119 + start program = "/usr/bin/sudo -u root /bin/bash -c 'cd /var/www/apps/errbit/current && /usr/bin/env bundle exec puma -C /var/www/apps/errbit/shared/puma.rb --daemon'"
  120 + stop program = "/usr/bin/sudo -u root /bin/bash -c 'cd /var/www/apps/errbit/current && /usr/bin/env bundle exec pumactl -S /var/www/apps/errbit/shared/tmp/pids/puma.state stop'"
  121 + if totalmem is greater than 2048 MB for 3 cycles then restart
  122 +```