From 3586fa6ae701fc3dcd7d33a6ef0e5f5c46bf1b67 Mon Sep 17 00:00:00 2001 From: Justin Ramos Date: Tue, 22 Nov 2016 21:01:12 +0000 Subject: [PATCH] allowing for graceful unicorn restarts closes #7217 --- Changelog.md | 1 + config/defaults.yml | 2 +- config/diaspora.yml.example | 4 ++-- config/eye.rb | 17 ++++++++++++++--- config/unicorn.rb | 18 ++++++++++++++++-- 5 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Changelog.md b/Changelog.md index 679a025c8..e37e70a31 100644 --- a/Changelog.md +++ b/Changelog.md @@ -28,6 +28,7 @@ * Update notifications every 5 minutes and when opening the notification dropdown [#6952](https://github.com/diaspora/diaspora/pull/6952) * Show browser notifications when receiving new unread notifications [#6952](https://github.com/diaspora/diaspora/pull/6952) * Only clear comment textarea when comment submission was successful [#7186](https://github.com/diaspora/diaspora/pull/7186) +* Add support for graceful unicorn restarts [#7217](https://github.com/diaspora/diaspora/pull/7217) # 0.6.1.0 diff --git a/config/defaults.yml b/config/defaults.yml index 853e37599..0caa76ceb 100644 --- a/config/defaults.yml +++ b/config/defaults.yml @@ -42,7 +42,7 @@ defaults: server: listen: '0.0.0.0:3000' rails_environment: 'development' - pid: + pid: "tmp/pids/web.pid" stderr_log: stdout_log: unicorn_worker: 2 diff --git a/config/diaspora.yml.example b/config/diaspora.yml.example index 93b0e014f..4457d18fe 100644 --- a/config/diaspora.yml.example +++ b/config/diaspora.yml.example @@ -177,8 +177,8 @@ configuration: ## Section #listen: 'unix:/run/diaspora/diaspora.sock' #listen: '127.0.0.1:3000' - ## Set the path for the PID file of the unicorn master process (default=none) - #pid: '/run/diaspora/diaspora.pid' + ## Set the path for the PID file of the unicorn master process (default=tmp/pids/web.pid) + #pid: 'tmp/pids/web.pid' ## Rails environment (default='development'). ## The environment in which the server should be started by default. diff --git a/config/eye.rb b/config/eye.rb index fdfbed198..fbc166709 100644 --- a/config/eye.rb +++ b/config/eye.rb @@ -12,10 +12,21 @@ Eye.application("diaspora") do stderr "log/eye_processes_stderr.log" process :web do - start_command "bin/bundle exec unicorn -c config/unicorn.rb" - daemonize true - pid_file "tmp/pids/web.pid" + unicorn_command = "bin/bundle exec unicorn -c config/unicorn.rb" + + if rails_env == "production" + start_command "#{unicorn_command} -D" + daemonize false + restart_command "kill -USR2 {PID}" + restart_grace 10.seconds + else + start_command unicorn_command + daemonize true + end + + pid_file AppConfig.server.pid.get stop_signals [:TERM, 10.seconds] + env "PORT" => ENV["PORT"] monitor_children do diff --git a/config/unicorn.rb b/config/unicorn.rb index 3877630cf..078797201 100644 --- a/config/unicorn.rb +++ b/config/unicorn.rb @@ -4,7 +4,7 @@ port = ENV["PORT"] port = port && !port.empty? ? port.to_i : nil listen port || AppConfig.server.listen.get unless RACKUP[:set_listener] -pid AppConfig.server.pid.get if AppConfig.server.pid? +pid AppConfig.server.pid.get worker_processes AppConfig.server.unicorn_worker.to_i timeout AppConfig.server.unicorn_timeout.to_i stderr_path AppConfig.server.stderr_log.get if AppConfig.server.stderr_log? @@ -26,11 +26,25 @@ before_fork do |_server, _worker| end end -after_fork do |_server, _worker| +after_fork do |server, worker| Logging.reopen # reopen logfiles to obtain a new file descriptor ActiveRecord::Base.establish_connection # preloading app in master, so reconnect to DB # We don't generate uuids in the frontend, but let's be on the safe side UUID.generator.next_sequence + + # Check for an old master process from a graceful restart + old_pid = "#{AppConfig.server.pid.get}.oldbin" + + if File.exist?(old_pid) && server.pid != old_pid + begin + # Remove a worker from the old master when we fork a new one (TTOU) + # Except for the last worker forked by this server, which kills the old master (QUIT) + signal = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU + Process.kill(signal, File.read(old_pid).to_i) + rescue Errno::ENOENT, Errno::ESRCH + # someone else did our job for us + end + end end