Skip to content

Fix runtime check for Puma v6

Stan Hu requested to merge sh-runtime-check-puma-v6 into master

What does this MR do and why?

https://github.com/puma/puma/pull/3061 renamed Rack::Handler::Puma to Puma::RackHandler. When bin/rails server initializes, it registers the Puma handler, which then defines the Puma module. However, this causes GitLab to think Puma v6 has started when only Rails itself has begun to load.

To avoid this problem, tighten up the runtime check by checking for Puma::Server, which is loaded when require 'puma' is run.

This change is compatible with both Puma v5 and v6 because Puma::Server is auto-loaded when require 'puma' is run (https://github.com/puma/puma/blob/v5.6.5/lib/puma.rb#L19, https://github.com/puma/puma/blob/v6.2.2/lib/puma.rb#L21). This happens in two cases:

  1. bin/puma is executed. The CLI calls require 'puma': https://github.com/puma/puma/blob/v5.6.5/lib/puma/cli.rb#L6, https://github.com/puma/puma/blob/v6.2.2/lib/puma/cli.rb#L6

  2. bin/rails server is executed. Rack::Handler attempts to load puma first via require 'rack/handler/puma' (https://github.com/rack/rack/blob/v2.2.7/lib/rack/handler.rb#L18). In Puma v5, this defines Rack::Handler::Puma, but in Puma v6, this defines Puma::RackHandler. As a result, even before Puma has been spawned, the Rails initializers will think the Puma runtime has been loaded (https://gitlab.com/gitlab-org/gitlab/-/blob/7243f8076bc2cab4e5827595bd1a909c62588423/config/initializers/memory_watchdog.rb#L9), but crash because the memory watchdog will attempt to access ::Puma.cli_config (https://gitlab.com/gitlab-org/gitlab/-/blob/537eed89ad46bb369cc301b26aef3ff969d7f669/lib/gitlab/memory/watchdog/handlers/puma_handler.rb#L11), which is nil.

In addition, https://github.com/puma/puma/pull/3035 dropped the use of the time gem in Puma, but our Puma JSON-formatter needs it.

How to set up and validate locally

  1. On master, restart puma with this branch (gdk restart rails-web). It should load fine.
  2. Run bin/rails server. This should also load fine.
  3. Upgrade to Puma v6 with this diff, and run bundle install.
diff --git a/Gemfile b/Gemfile
index 68bd5bc0cf72..a363a4a49043 100644
--- a/Gemfile
+++ b/Gemfile
@@ -212,7 +212,7 @@ gem 'rack', '~> 2.2.7'
 gem 'rack-timeout', '~> 0.6.3', require: 'rack/timeout/base'
 
 group :puma do
-  gem 'puma', '~> 5.6.5', require: false
+  gem 'puma', '~> 6', require: false
   gem 'puma_worker_killer', '~> 0.3.1', require: false
   gem 'sd_notify', '~> 0.1.0', require: false
 end
diff --git a/Gemfile.lock b/Gemfile.lock
index db33c7f3d5a3..9ddbd067343d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1169,7 +1169,7 @@ GEM
       tty-markdown
       tty-prompt
     public_suffix (5.0.0)
-    puma (5.6.5)
+    puma (6.2.2)
       nio4r (~> 2.0)
     puma_worker_killer (0.3.1)
       get_process_mem (~> 0.2)
@@ -1874,7 +1874,7 @@ DEPENDENCIES
   pry-byebug
   pry-rails (~> 0.3.9)
   pry-shell (~> 0.6.1)
-  puma (~> 5.6.5)
+  puma (~> 6)
   puma_worker_killer (~> 0.3.1)
   rack (~> 2.2.7)
   rack-attack (~> 6.6.1)
  1. Restart puma. This should load fine.
  2. Run bin/rails server. This should crash. 💥
  3. Check out this branch and repeat steps 3 and 4. Both should work.

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Stan Hu

Merge request reports