Signal handling
In general, signals need only be sent to the master process. However, the
signals Rainbows! uses internally to
communicate with the worker processes are documented here as well. With the
exception of TTIN/TTOU, signal handling matches the behavior of and nginx so it should be possible to easily share
process management scripts between \Rainbows!, unicorn and nginx.
Master Process
- HUP - reload config file, app, and gracefully restart all workers If the
"preload_app" directive is false (the default), then workers will
also pick up any application code changes when restarted. If
"preload_app" is true, then application code changes will have no
effect; USR2 + QUIT (see below) must be used to load newer code in this
case. When reloading the application, +Gem.refresh+ will be called so
updated code for your application can pick up newly installed RubyGems. It
is not recommended that you uninstall libraries your application depends on
while Rainbows! is running, as
respawned workers may enter a spawn loop when they fail to load an
uninstalled dependency.
- INT/TERM - quick shutdown, kills all workers immediately
- QUIT - graceful shutdown, waits for workers to finish their current request
before finishing. Since Rainbows
5.1.0 (Jan 2017), this waits requests deferred to a separate thread with
EventMachine (app.deferred?(env) => true).
- USR1 - reopen all logs owned by the master and all workers See
Unicorn::Util.reopen_logs for what is considered a log.
- USR2 - reexecute the running binary. A separate QUIT should be sent to the
original process once the child is verified to be up and running.
- WINCH - gracefully stops workers but keep the master running. This will
only work for daemonized processes.
- TTIN - increment the number of worker processes by one
- TTOU - decrement the number of worker processes by one
Worker Processes
Sending signals directly to the worker processes should not normally be
needed. If the master process is running, any exited worker will be
automatically respawned.
- INT/TERM - Quick shutdown, immediately exit. Unless WINCH has been sent to
the master (or the master is killed), the master process will respawn a
worker to replace this one.
- QUIT - Gracefully exit after finishing the current request. Unless WINCH
has been sent to the master (or the master is killed), the master process
will respawn a worker to replace this one. This currently does not wait for
requests deferred to a separate thread when using EventMachine (when
app.deferred?(env) => true)
- USR1 - Reopen all logs owned by the worker process. See
Unicorn::Util.reopen_logs for what is considered a log. Unlike unicorn, log
files are reopened immediately in \Rainbows! since worker processes are
likely to be serving multiple clients simutaneously, we can‘t wait
for all of them to finish.
Procedure to replace a running rainbows executable
You may replace a running instance of rainbows with a new one without
losing any incoming connections. Doing so will reload all of your
application code, unicorn/Rainbows! config, Ruby executable, and all
libraries. The only things that will not change (due to OS limitations)
are:
- The path to the rainbows executable script. If you want to change to a
different installation of Ruby, you can modify the shebang line to point to
your alternative interpreter.
The procedure is exactly like that of nginx:
- Send USR2 to the master process
- Check your process manager or pid files to see if a new master spawned
successfully. If you‘re using a pid file, the old process will have
".oldbin" appended to its path. You should have two master
instances of rainbows running now, both of which will have workers
servicing requests. Your process tree should look something like this:
rainbows master (old)
\_ rainbows worker[0]
\_ rainbows worker[1]
\_ rainbows worker[2]
\_ rainbows worker[3]
\_ rainbows master
\_ rainbows worker[0]
\_ rainbows worker[1]
\_ rainbows worker[2]
\_ rainbows worker[3]
- You can now send WINCH to the old master process so only the new workers
serve requests. If your rainbows process is bound to an interactive
terminal, you can skip this step. Step 5 will be more difficult but you can
also skip it if your process is not daemonized.
- You should now ensure that everything is running correctly with the new
workers as the old workers die off.
- If everything seems ok, then send QUIT to the old master. You‘re
done!
If something is broken, then send HUP to the old master to reload the
config and restart its workers. Then send QUIT to the new master process.