Commit 4964372e7ca61b592d5d28f33aec4bc6b3ea57b0
Exists in
master
Merge pull request #1005 from otzy007/puma
Use puma instead of unicorn
Showing
11 changed files
with
94 additions
and
116 deletions
Show diff stats
.env.default
| @@ -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 |
Capfile
| @@ -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 } |
Gemfile
| @@ -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' |
Gemfile.lock
| @@ -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 |
Procfile
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 | # 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' |
| @@ -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 | +``` |