diff --git a/docs/fork_worker.md b/docs/fork_worker.md index f2afb25739..c756f6a97a 100644 --- a/docs/fork_worker.md +++ b/docs/fork_worker.md @@ -10,7 +10,7 @@ Puma 5 introduces an experimental new cluster-mode configuration option, `fork_w 10004 \_ puma: cluster worker 3: 10000 [puma] ``` -Similar to the `preload_app!` option, the `fork_worker` option allows your application to be initialized only once for copy-on-write memory savings, and it has two additional advantages: +The `fork_worker` option allows your application to be initialized only once for copy-on-write memory savings, and it has two additional advantages: 1. **Compatible with phased restart.** Because the master process itself doesn't preload the application, this mode works with phased restart (`SIGUSR1` or `pumactl phased-restart`). When worker 0 reloads as part of a phased restart, it initializes a new copy of your application first, then the other workers reload by forking from this new worker already containing the new preloaded application. @@ -24,8 +24,6 @@ Similar to the `preload_app!` option, the `fork_worker` option allows your appli ### Limitations -- Not compatible with the `preload_app!` option - - This mode is still very experimental so there may be bugs or edge-cases, particularly around expected behavior of existing hooks. Please open a [bug report](https://github.com/puma/puma/issues/new?template=bug_report.md) if you encounter any issues. - In order to fork new workers cleanly, worker 0 shuts down its server and stops serving requests so there are no open file descriptors or other kinds of shared global state between processes, and to maximize copy-on-write efficiency across the newly-forked workers. This may temporarily reduce total capacity of the cluster during a phased restart / refork. diff --git a/lib/puma/cluster.rb b/lib/puma/cluster.rb index 6b8fc4594c..99e134c118 100644 --- a/lib/puma/cluster.rb +++ b/lib/puma/cluster.rb @@ -213,8 +213,8 @@ def restart stop end - def phased_restart - return false if @options[:preload_app] + def phased_restart(refork = false) + return false if @options[:preload_app] && !refork @phased_restart = true wakeup! @@ -281,7 +281,7 @@ def fork_worker! if (worker = @workers.find { |w| w.index == 0 }) worker.phase += 1 end - phased_restart + phased_restart(true) end # We do this in a separate method to keep the lambda scope