-
Notifications
You must be signed in to change notification settings - Fork 332
Forking
This page was started from an issue asking about how sneakers uses forking: https://github.com/jondot/sneakers/issues/437 - most of the answer is currently based on jbielick's initial investigation
If you have connections that need to be re-established for each child process, you may be wondering whether sneakers forks child processes, and where you might hook into the forking mechanism to perform necessary tear-down steps for the parent or setup steps for the child process.
There's quite a lot of process management built into serverengine, which sneakers uses for forking and threading.
If you're familiar with systemd (or any other supervision or containerization tool) for process management, the default forking behavior here may be unexpected and a little annoying. Here's the diagram from serverengine's README:
Heartbeat via pipe
& auto-restart
/ \ ---+
+------------+ / +----------+ \ +--------+ |
| Supervisor |------| Server |------| Worker | |
+------------+ +----------+\ +--------+ | Multi-process
/ \ | or multi-thread
/ \ +--------+ |
Dynamic reconfiguration | Worker | |
and live restart support +--------+ |
---+
The primary setting we've found to control the forking is the workers
setting. Any number of workers > 1 would be "multi-process", in which there are multiple processes being managed for the one parent that you started.
If you're using a process supervisor like upstart, systemd, containers, etc, you'll want workers: 1
in your sneakers config. daemonize: false
is the other option you'll probably want so the process stays in the foreground.
With workers: 1
, you'll still get a single forked process. When you're using upstart, it might require some extra options to track the fork instead of the parent. (This line in sneakers provides worker_type as process
to serverengine. Which produces a MultiProcessServer
which inevitably forks at least 1 time)
So if it always forks, where can you define logic that needs to run in the child process (e.g. to re-establish a database connection)?
This part is not well documented (if you blinked while reading, you may have missed it), but if you look at the configuration docs, you'll notice a worker configuration called "hooks". The available sub-options are before_fork
and after_fork
:
So if you need to close and reestablish a Mongo connection, for instance, you might do something like this:
hooks: {
before_fork: lambda do
Mongoid.disconnect_clients
end,
after_fork: lambda do
Mongoid::Clients.clients.each do |_name, client|
client.close
client.reconnect
end
end
}