diff --git a/Gemfile b/Gemfile index 95cb04f0a8d..6fb5ac813ca 100644 --- a/Gemfile +++ b/Gemfile @@ -126,6 +126,9 @@ group :production do # requires memcached 1.4+ # see https://github.clientom/mperham/dalli gem 'dalli', '~> 2.7.6' + + # Unicorn worker killer to restart unicorn child workers + gem 'unicorn-worker-killer', require: false end gem 'sprockets', '~> 3.7.0' diff --git a/Gemfile.lock b/Gemfile.lock index d57ba26ba21..ef7812c928a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -288,6 +288,7 @@ GEM fuubar (2.2.0) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) + get_process_mem (0.2.1) gherkin (4.0.0) globalid (0.3.7) activesupport (>= 4.1.0) @@ -560,6 +561,9 @@ GEM unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) + unicorn-worker-killer (0.4.4) + get_process_mem (~> 0) + unicorn (>= 4, < 6) url (0.3.2) virtus (1.0.5) axiom-types (~> 0.1) @@ -698,6 +702,7 @@ DEPENDENCIES transactional_lock! tzinfo-data (~> 1.2016.1) unicorn + unicorn-worker-killer warden (~> 1.2) warden-basic_auth (~> 0.2.1) webmock (~> 2.1.0) diff --git a/config.ru b/config.ru index 6c313e9fa62..5797be10d1e 100644 --- a/config.ru +++ b/config.ru @@ -31,6 +31,23 @@ require ::File.expand_path('../config/environment', __FILE__) +## +# Use the worker killer when Unicorn is being used +if defined?(Unicorn) && Rails.env.production? + require 'unicorn/worker_killer' + + min_ram = ENV.fetch('OPENPROJECT_UNICORN_RAM2KILL_MIN', 340 * 1 << 20).to_i + max_ram = ENV.fetch('OPENPROJECT_UNICORN_RAM2KILL_MAX', 400 * 1 << 20).to_i + min_req = ENV.fetch('OPENPROJECT_UNICORN_REQ2KILL_MIN', 3072).to_i + max_req = ENV.fetch('OPENPROJECT_UNICORN_REQ2KILL_MAX', 4096).to_i + + # Kill Workers randomly between 340 and 400 MB (per default) + # or between 3072 and 4096 requests. + # Our largest installations are starting around 200/230 MB + use Unicorn::WorkerKiller::Oom, min_ram, max_ram + use Unicorn::WorkerKiller::MaxRequests, min_req, max_req +end + ## # Returns true if the application should be run under a subdirectory. def map_subdir?