Skip to content
Joe Marty edited this page Jul 9, 2020 · 4 revisions

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.

ServerEngine

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         +--------+     |
                                                  ---+

Process/Forking Configuration

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)

Forking Hooks

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:

Sneakers.configure ...
  hooks: {
    before_fork: ...
    after_fork: ...
  }

Each of them accepts a proc as values, so if you need to close and re-establish a MongoId connection, 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
  }