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
.env.default
... ... @@ -23,8 +23,3 @@ GITHUB_API_URL=https://api.github.com
23 23 GITHUB_ACCESS_SCOPE='[repo]'
24 24 GITHUB_SITE_TITLE=GitHub
25 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
... ...
Capfile
... ... @@ -4,5 +4,6 @@ require 'capistrano/deploy'
4 4 require 'capistrano/rbenv' if ENV['rbenv']
5 5 require 'capistrano/bundler'
6 6 require 'capistrano/rails/assets'
  7 +require 'capistrano/puma'
7 8  
8 9 Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
... ...
Gemfile
... ... @@ -76,6 +76,7 @@ group :development do
76 76 gem 'capistrano-bundler', require: false
77 77 gem 'capistrano-rails', require: false
78 78 gem 'capistrano-rbenv', require: false
  79 + gem 'capistrano3-puma', require: false
79 80  
80 81 # better errors
81 82 gem 'better_errors'
... ... @@ -100,10 +101,9 @@ end
100 101  
101 102 group :heroku, :production do
102 103 gem 'rails_12factor', require: ENV.key?("HEROKU")
103   - gem 'unicorn', require: false, platform: 'ruby'
104   - gem 'unicorn-worker-killer'
105 104 end
106 105  
  106 +gem 'puma'
107 107 gem 'therubyracer', platform: :ruby # C Ruby (MRI) or Rubinius, but NOT Windows
108 108 gem 'sass-rails'
109 109 gem 'uglifier'
... ...
Gemfile.lock
... ... @@ -76,6 +76,9 @@ GEM
76 76 capistrano-rbenv (2.0.3)
77 77 capistrano (~> 3.1)
78 78 sshkit (~> 1.3)
  79 + capistrano3-puma (1.2.1)
  80 + capistrano (~> 3.0)
  81 + puma (>= 2.6)
79 82 capybara (2.4.4)
80 83 mime-types (>= 1.16)
81 84 nokogiri (>= 1.3.3)
... ... @@ -134,7 +137,6 @@ GEM
134 137 multi_json
135 138 font-awesome-rails (4.2.0.0)
136 139 railties (>= 3.2, < 5.0)
137   - get_process_mem (0.2.0)
138 140 globalid (0.3.6)
139 141 activesupport (>= 4.1.0)
140 142 haml (4.0.6)
... ... @@ -165,7 +167,6 @@ GEM
165 167 kaminari (0.16.3)
166 168 actionpack (>= 3.0.0)
167 169 activesupport (>= 3.0.0)
168   - kgio (2.9.3)
169 170 launchy (2.4.3)
170 171 addressable (~> 2.3)
171 172 launchy (2.4.3-java)
... ... @@ -258,6 +259,7 @@ GEM
258 259 pry (~> 0.10)
259 260 pry-rails (0.3.4)
260 261 pry (>= 0.9.10)
  262 + puma (2.15.3)
261 263 quiet_assets (1.1.0)
262 264 railties (>= 3.1, < 5.0)
263 265 rack (1.6.4)
... ... @@ -300,7 +302,6 @@ GEM
300 302 rake (>= 0.8.7)
301 303 thor (>= 0.18.1, < 2.0)
302 304 rainbow (2.0.0)
303   - raindrops (0.13.0)
304 305 rake (10.4.2)
305 306 ref (1.0.5)
306 307 request_store (1.1.0)
... ... @@ -398,13 +399,6 @@ GEM
398 399 unf_ext
399 400 unf (0.1.4-java)
400 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 402 useragent (0.14.0)
409 403 warden (1.2.3)
410 404 rack (>= 1.0)
... ... @@ -434,6 +428,7 @@ DEPENDENCIES
434 428 capistrano-bundler
435 429 capistrano-rails
436 430 capistrano-rbenv
  431 + capistrano3-puma
437 432 capybara
438 433 coveralls
439 434 decent_exposure
... ... @@ -465,6 +460,7 @@ DEPENDENCIES
465 460 poltergeist
466 461 pry-byebug
467 462 pry-rails
  463 + puma
468 464 quiet_assets
469 465 rack-ssl
470 466 rack-ssl-enforcer
... ... @@ -483,8 +479,6 @@ DEPENDENCIES
483 479 timecop
484 480 uglifier
485 481 underscore-rails
486   - unicorn
487   - unicorn-worker-killer
488 482 useragent
489 483 xmpp4r
490 484 yajl-ruby
... ...
Procfile
1   -web: bundle exec unicorn -c ./config/unicorn.default.rb
  1 +web: bundle exec puma -C config/puma.default.rb
... ...
config.ru
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 1 # This file is used by Rack-based servers to start the application.
12 2  
13 3 require ::File.expand_path('../config/environment', __FILE__)
... ...
config/deploy.example.rb
... ... @@ -21,7 +21,7 @@ set :ssh_options, forward_agent: true
21 21 set :linked_files, fetch(:linked_files, []) + %w(
22 22 .env
23 23 config/newrelic.yml
24   - config/unicorn.rb
  24 + config/puma.rb
25 25 )
26 26  
27 27 set :linked_dirs, fetch(:linked_dirs, []) + %w(
... ... @@ -45,13 +45,14 @@ namespace :errbit do
45 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 49 }.each do |src, target|
51 50 unless test("[ -f #{shared_path}/#{target} ]")
52 51 upload! src, "#{shared_path}/#{target}"
53 52 end
54 53 end
  54 +
  55 + invoke 'puma:config'
55 56 end
56 57 end
57 58 end
... ... @@ -69,47 +70,5 @@ namespace :db do
69 70 end
70 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 @@
  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   -# 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 5 to fill in any values that you can't or won't supply through the environment.
6 6  
7 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 9 2. Values provided in a .env file
10 10 3. Default values from .env.default
11 11  
... ... @@ -100,10 +100,4 @@ In order of precedence Errbit uses:
100 100 <dt>DEVISE_MODULES
101 101 <dd>Devise modules to enable
102 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 103 </dl>
... ...
docs/deployment/capistrano.md
... ... @@ -43,7 +43,20 @@ Errbit comes with some capistrano tasks to manage running Errbit under
43 43 unicorn.
44 44 To start Errbit, you can run:
45 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 62 Supervising and monitoring Errbit is beyond the scope of this
... ... @@ -63,3 +76,47 @@ rbenv=1 bundle exec cap production deploy
63 76 ## Schedule recurring tasks
64 77 You may want to periodically clear resolved errors to free up space.
65 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 +```
... ...