From e438b907def6702bd1ec35cbf8c623ba12c5e19e Mon Sep 17 00:00:00 2001 From: Jean byroot Boussier Date: Thu, 15 Sep 2022 03:30:55 +0200 Subject: [PATCH] Allow to use `preload_app!` with `fork_worker` (#2907) So far it was incompatible because true phased restart are incompatible with preload_app. But `fork_worker` doesn't do a phased restart per say, it just piggy back on the implementation to ask worker #0 to refork its siblings. So we can just bypass that check and it works. Co-authored-by: Jean Boussier --- docs/fork_worker.md | 4 +--- lib/puma/cluster.rb | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/fork_worker.md b/docs/fork_worker.md index f2afb257..c756f6a9 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 6b8fc459..99e134c1 100644 --- a/lib/puma/cluster.rb +++ b/lib/puma/cluster.rb @@ -213,8 +213,8 @@ module Puma 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 @@ module Puma 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