Skip to content

Conversation

@dependabot
Copy link
Contributor

@dependabot dependabot bot commented on behalf of github Jan 22, 2026

Bumps puma from 7.1.0 to 7.2.0.

Release notes

Sourced from puma's releases.

v7.2.0

7.2.0 On The Corner

  • Features

    • Add workers :auto (#3827)
    • Make it possible to restrict control server commands to stats (#3787)
  • Bugfixes

    • Don't break if WEB_CONCURRENCY is set to a blank string (#3837)
    • Don't share server between worker 0 and descendants on refork (#3602)
    • Fix phase check race condition in Puma::Cluster#check_workers (#3690)
    • Fix advertising of CLI config before config files are loaded (#3823)
  • Performance

    • 17% faster HTTP parsing through pre-interning env keys (#3825)
    • Implement dsize and dcompact functions for Puma::HttpParser, which makes Puma's C-extension GC-compactible (#3828)
  • Refactor

    • Remove NoMethodError rescue in Reactor#select_loop (#3831)
    • Various cleanups in the C extension (#3814)
    • Monomorphize handle_request return (#3802)
  • Docs

    • Change link to docs/deployment.md in README.md (#3848)
    • Fix formatting for each signal description in signals.md (#3813)
    • Update deployment and Kubernetes docs with Puma configuration tips (#3807)
    • Rename master to main (#3809, #3808, #3800)
    • Fix some minor typos in the docs (#3804)
    • Add GOVERNANCE.md, MAINTAINERS (#3826)
    • Remove Code Climate badge (#3820)
    • Add @​joshuay03 to the maintainer list
  • CI

New Contributors

Full Changelog: puma/puma@v7.1.0...v7.2.0

Changelog

Sourced from puma's changelog.

7.2.0 / 2026-01-20

  • Features

    • Add workers :auto (#3827)
    • Make it possible to restrict control server commands to stats (#3787)
  • Bugfixes

    • Don't break if WEB_CONCURRENCY is set to a blank string (#3837)
    • Don't share server between worker 0 and descendants on refork (#3602)
    • Fix phase check race condition in Puma::Cluster#check_workers (#3690)
    • Fix advertising of CLI config before config files are loaded (#3823)
  • Performance

    • 17% faster HTTP parsing through pre-interning env keys (#3825)
    • Implement dsize and dcompact functions for Puma::HttpParser, which makes Puma's C-extension GC-compactible (#3828)
  • Refactor

    • Remove NoMethodError rescue in Reactor#select_loop (#3831)
    • Various cleanups in the C extension (#3814)
    • Monomorphize handle_request return (#3802)
  • Docs

    • Change link to docs/deployment.md in README.md (#3848)
    • Fix formatting for each signal description in signals.md (#3813)
    • Update deployment and Kubernetes docs with Puma configuration tips (#3807)
    • Rename master to main (#3809, #3808, #3800)
    • Fix some minor typos in the docs (#3804)
    • Add GOVERNANCE.md, MAINTAINERS (#3826)
    • Remove Code Climate badge (#3820)
    • Add @​joshuay03 to the maintainer list
  • CI

Commits

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [puma](https://github.com/puma/puma) from 7.1.0 to 7.2.0.
- [Release notes](https://github.com/puma/puma/releases)
- [Changelog](https://github.com/puma/puma/blob/main/History.md)
- [Commits](puma/puma@v7.1.0...v7.2.0)

---
updated-dependencies:
- dependency-name: puma
  dependency-version: 7.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot bot added dependencies ruby Pull requests that update Ruby code labels Jan 22, 2026
@github-actions
Copy link
Contributor

4 similar comments
@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

gem compare puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT metadata:
    7.1.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/master/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
    7.2.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/main/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
  DIFFERENT require_paths:
    7.1.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.1.0", "lib"]
    7.2.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.2.0", "lib"]
  DIFFERENT rubygems_version:
    7.1.0: 3.6.9
    7.2.0: 4.0.3
  DIFFERENT version:
    7.1.0: 7.1.0
    7.2.0: 7.2.0
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
            History.md +71/-0
            README.md +17/-9
            docs/deployment.md +58/-23
            docs/jungle/README.md +1/-1
            docs/kubernetes.md +3/-10
            docs/plugins.md +2/-2
            docs/signals.md +10/-10
            docs/stats.md +1/-1
            docs/systemd.md +3/-3
            ext/puma_http11/puma_http11.c +101/-109
            lib/puma/app/status.rb +10/-2
            lib/puma/cluster.rb +2/-3
            lib/puma/cluster/worker.rb +10/-9
            lib/puma/configuration.rb +16/-9
            lib/puma/const.rb +2/-2
            lib/puma/dsl.rb +16/-6
            lib/puma/launcher.rb +4/-3
            lib/puma/reactor.rb +3/-12
            lib/puma/request.rb +10/-8
            lib/puma/runner.rb +1/-1
            lib/puma/server.rb +3/-3
            lib/puma/single.rb +2/-2
            tools/Dockerfile +13/-5

3 similar comments
@github-actions
Copy link
Contributor

gem compare puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT metadata:
    7.1.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/master/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
    7.2.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/main/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
  DIFFERENT require_paths:
    7.1.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.1.0", "lib"]
    7.2.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.2.0", "lib"]
  DIFFERENT rubygems_version:
    7.1.0: 3.6.9
    7.2.0: 4.0.3
  DIFFERENT version:
    7.1.0: 7.1.0
    7.2.0: 7.2.0
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
            History.md +71/-0
            README.md +17/-9
            docs/deployment.md +58/-23
            docs/jungle/README.md +1/-1
            docs/kubernetes.md +3/-10
            docs/plugins.md +2/-2
            docs/signals.md +10/-10
            docs/stats.md +1/-1
            docs/systemd.md +3/-3
            ext/puma_http11/puma_http11.c +101/-109
            lib/puma/app/status.rb +10/-2
            lib/puma/cluster.rb +2/-3
            lib/puma/cluster/worker.rb +10/-9
            lib/puma/configuration.rb +16/-9
            lib/puma/const.rb +2/-2
            lib/puma/dsl.rb +16/-6
            lib/puma/launcher.rb +4/-3
            lib/puma/reactor.rb +3/-12
            lib/puma/request.rb +10/-8
            lib/puma/runner.rb +1/-1
            lib/puma/server.rb +3/-3
            lib/puma/single.rb +2/-2
            tools/Dockerfile +13/-5

@github-actions
Copy link
Contributor

gem compare puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT metadata:
    7.1.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/master/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
    7.2.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/main/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
  DIFFERENT require_paths:
    7.1.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.1.0", "lib"]
    7.2.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.2.0", "lib"]
  DIFFERENT rubygems_version:
    7.1.0: 3.6.9
    7.2.0: 4.0.3
  DIFFERENT version:
    7.1.0: 7.1.0
    7.2.0: 7.2.0
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
            History.md +71/-0
            README.md +17/-9
            docs/deployment.md +58/-23
            docs/jungle/README.md +1/-1
            docs/kubernetes.md +3/-10
            docs/plugins.md +2/-2
            docs/signals.md +10/-10
            docs/stats.md +1/-1
            docs/systemd.md +3/-3
            ext/puma_http11/puma_http11.c +101/-109
            lib/puma/app/status.rb +10/-2
            lib/puma/cluster.rb +2/-3
            lib/puma/cluster/worker.rb +10/-9
            lib/puma/configuration.rb +16/-9
            lib/puma/const.rb +2/-2
            lib/puma/dsl.rb +16/-6
            lib/puma/launcher.rb +4/-3
            lib/puma/reactor.rb +3/-12
            lib/puma/request.rb +10/-8
            lib/puma/runner.rb +1/-1
            lib/puma/server.rb +3/-3
            lib/puma/single.rb +2/-2
            tools/Dockerfile +13/-5

@github-actions
Copy link
Contributor

gem compare puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT metadata:
    7.1.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/master/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
    7.2.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/main/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
  DIFFERENT require_paths:
    7.1.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.1.0", "lib"]
    7.2.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.2.0", "lib"]
  DIFFERENT rubygems_version:
    7.1.0: 3.6.9
    7.2.0: 4.0.3
  DIFFERENT version:
    7.1.0: 7.1.0
    7.2.0: 7.2.0
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
            History.md +71/-0
            README.md +17/-9
            docs/deployment.md +58/-23
            docs/jungle/README.md +1/-1
            docs/kubernetes.md +3/-10
            docs/plugins.md +2/-2
            docs/signals.md +10/-10
            docs/stats.md +1/-1
            docs/systemd.md +3/-3
            ext/puma_http11/puma_http11.c +101/-109
            lib/puma/app/status.rb +10/-2
            lib/puma/cluster.rb +2/-3
            lib/puma/cluster/worker.rb +10/-9
            lib/puma/configuration.rb +16/-9
            lib/puma/const.rb +2/-2
            lib/puma/dsl.rb +16/-6
            lib/puma/launcher.rb +4/-3
            lib/puma/reactor.rb +3/-12
            lib/puma/request.rb +10/-8
            lib/puma/runner.rb +1/-1
            lib/puma/server.rb +3/-3
            lib/puma/single.rb +2/-2
            tools/Dockerfile +13/-5

@github-actions
Copy link
Contributor

gem compare --diff puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
        History.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/History.md	2026-01-22 03:33:09.909766938 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/History.md	2026-01-22 03:33:09.922766861 +0000
                @@ -0,0 +1,35 @@
                +## 7.2.0 / 2026-01-20
                +
                +* Features
                +  * Add workers `:auto` ([#3827])
                +  * Make it possible to restrict control server commands to stats ([#3787])
                +
                +* Bugfixes
                +  * Don't break if `WEB_CONCURRENCY` is set to a blank string ([#3837])
                +  * Don't share server between worker 0 and descendants on refork ([#3602])
                +  * Fix phase check race condition in `Puma::Cluster#check_workers` ([#3690])
                +  * Fix advertising of CLI config before config files are loaded ([#3823])
                +
                +* Performance
                +  * 17% faster HTTP parsing through pre-interning env keys ([#3825])
                +  * Implement `dsize` and `dcompact` functions for `Puma::HttpParser`, which makes Puma's C-extension GC-compactible ([#3828])
                +
                +* Refactor
                +  * Remove `NoMethodError` rescue in `Reactor#select_loop` ([#3831])
                +  * Various cleanups in the C extension ([#3814])
                +  * Monomorphize `handle_request` return ([#3802])
                +
                +* Docs
                +  * Change link to `docs/deployment.md` in `README.md` ([#3848])
                +  * Fix formatting for each signal description in signals.md ([#3813])
                +  * Update deployment and Kubernetes docs with Puma configuration tips ([#3807])
                +  * Rename master to main ([#3809], [#3808], [#3800])
                +  * Fix some minor typos in the docs ([#3804])
                +  * Add `GOVERNANCE.md`, `MAINTAINERS` ([#3826])
                +  * Remove Code Climate badge ([#3820])
                +  * Add @joshuay03 to the maintainer list
                +
                +* CI
                +  * Use Minitest 6 where applicable ([#3859])
                +  * Many test suite improvements and flake fixes ([#3861], [#3863], [#3860], [#3852], [#3857], [#3856], [#3845], [#3843], [#3842], [#3841], [#3822], [#3817], [#3764])
                +
                @@ -2260,0 +2296,36 @@
                +
                +[#3863]:https://github.com/puma/puma/pull/3863     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3861]:https://github.com/puma/puma/pull/3861     "PR by MSP-Greg, merged 2026-01-20"
                +[#3860]:https://github.com/puma/puma/pull/3860     "PR by MSP-Greg, merged 2026-01-16"
                +[#3859]:https://github.com/puma/puma/pull/3859     "PR by MSP-Greg, merged 2026-01-16"
                +[#3857]:https://github.com/puma/puma/pull/3857     "PR by Aaron Patterson, merged 2026-01-12"
                +[#3856]:https://github.com/puma/puma/pull/3856     "PR by MSP-Greg, merged 2026-01-12"
                +[#3852]:https://github.com/puma/puma/pull/3852     "PR by Miłosz Bieniek, merged 2026-01-14"
                +[#3848]:https://github.com/puma/puma/pull/3848     "PR by Miłosz Bieniek, merged 2025-12-27"
                +[#3845]:https://github.com/puma/puma/pull/3845     "PR by MSP-Greg, merged 2025-12-19"
                +[#3843]:https://github.com/puma/puma/pull/3843     "PR by MSP-Greg, merged 2025-12-18"
                +[#3842]:https://github.com/puma/puma/pull/3842     "PR by MSP-Greg, merged 2025-12-18"
                +[#3841]:https://github.com/puma/puma/pull/3841     "PR by MSP-Greg, merged 2025-12-18"
                +[#3837]:https://github.com/puma/puma/pull/3837     "PR by John Bachir, merged 2026-01-09"
                +[#3833]:https://github.com/puma/puma/pull/3833     "PR by Patrik Ragnarsson, merged 2025-11-25"
                +[#3831]:https://github.com/puma/puma/pull/3831     "PR by Joshua Young, merged 2025-11-25"
                +[#3828]:https://github.com/puma/puma/pull/3828     "PR by Jean Boussier, merged 2025-11-21"
                +[#3827]:https://github.com/puma/puma/pull/3827     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3826]:https://github.com/puma/puma/pull/3826     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3825]:https://github.com/puma/puma/pull/3825     "PR by Jean Boussier, merged 2025-11-19"
                +[#3823]:https://github.com/puma/puma/pull/3823     "PR by Joshua Young, merged 2025-11-18"
                +[#3822]:https://github.com/puma/puma/pull/3822     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3820]:https://github.com/puma/puma/pull/3820     "PR by Nate Berkopec, merged 2025-11-19"
                +[#3817]:https://github.com/puma/puma/pull/3817     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3814]:https://github.com/puma/puma/pull/3814     "PR by Jean Boussier, merged 2025-11-17"
                +[#3813]:https://github.com/puma/puma/pull/3813     "PR by Masafumi Koba, merged 2025-11-17"
                +[#3809]:https://github.com/puma/puma/pull/3809     "PR by Patrik Ragnarsson, merged 2025-10-26"
                +[#3808]:https://github.com/puma/puma/pull/3808     "PR by Nymuxyzo, merged 2025-10-26"
                +[#3807]:https://github.com/puma/puma/pull/3807     "PR by Nate Berkopec, merged 2025-10-28"
                +[#3804]:https://github.com/puma/puma/pull/3804     "PR by Joe Rafaniello, merged 2025-10-21"
                +[#3802]:https://github.com/puma/puma/pull/3802     "PR by Richard Schneeman, merged 2025-10-20"
                +[#3800]:https://github.com/puma/puma/pull/3800     "PR by MSP-Greg, merged 2025-10-19"
                +[#3787]:https://github.com/puma/puma/pull/3787     "PR by Stan Hu, merged 2025-10-17"
                +[#3764]:https://github.com/puma/puma/pull/3764     "PR by MSP-Greg, merged 2025-10-17"
                +[#3690]:https://github.com/puma/puma/pull/3690     "PR by Joshua Young, merged 2025-11-18"
                +[#3602]:https://github.com/puma/puma/pull/3602     "PR by Joshua Young, merged 2025-11-28"
        README.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/README.md	2026-01-22 03:33:09.909766938 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/README.md	2026-01-22 03:33:09.922766861 +0000
                @@ -7,2 +7 @@
                -[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amaster)
                -[![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
                +[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amain)
                @@ -85 +84 @@
                -Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb).
                +Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb).
                @@ -88 +87 @@
                -[test](https://github.com/puma/puma/tree/master/test/config) suite.
                +[test](https://github.com/puma/puma/tree/main/test/config) suite.
                @@ -118,0 +118,9 @@
                +When using a config file, most applications can simply set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of worker processes to the available processors:
                +
                +```ruby
                +# config/puma.rb
                +workers :auto
                +```
                +
                +See [`workers :auto` gotchas](lib/puma/dsl.rb).
                +
                @@ -121 +129 @@
                -If the `WEB_CONCURRENCY` environment variable is set to `"auto"` and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#available_processor_count-class_method).
                +If `workers` is set to `:auto`, or the `WEB_CONCURRENCY` environment variable is set to `"auto"`, and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://msp-greg.github.io/concurrent-ruby/Concurrent.html#available_processor_count-class_method).
                @@ -123 +131 @@
                -For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](https://github.com/puma/puma/blob/9282a8efa5a0c48e39c60d22ca70051a25df9f55/docs/kubernetes.md#workers-per-pod-and-other-config-issues).
                +For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](docs/deployment.md).
                @@ -229 +237 @@
                -textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
                +textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/main/lib/puma/server.rb)).
                @@ -388 +396 @@
                -Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the status app has available.
                +Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/main/lib/puma/app/status.rb) to see what the status app has available.
                @@ -420 +428 @@
                -Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to see all available options.
                +Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb) to see all available options.
        docs/deployment.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/deployment.md	2026-01-22 03:33:09.910766932 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/deployment.md	2026-01-22 03:33:09.923766855 +0000
                @@ -18,0 +19,7 @@
                +In general, use single mode only if:
                +
                +* You are using JRuby, TruffleRuby or another fully-multithreaded implementation of Ruby
                +* You are using MRI but in an environment where only 1 CPU core is available.
                +
                +Otherwise, you'll want to use cluster mode to utilize all available CPU resources.
                +
                @@ -22 +29 @@
                -Here are some tips for cluster mode:
                +## Cluster Mode Tips
                @@ -24 +31 @@
                -### MRI
                +For the purposes of Puma provisioning, "CPU cores" means:
                @@ -26,4 +33,2 @@
                -* Use cluster mode and set the number of workers to 1.5x the number of CPU cores
                -  in the machine, starting from a minimum of 2.
                -* Set the number of threads to desired concurrent requests/number of workers.
                -  Puma defaults to 5, and that's a decent number.
                +1. On ARM, the number of physical cores.
                +2. On x86, the number of logical cores, hyperthreads, or vCPUs (these words all mean the same thing).
                @@ -31 +36 @@
                -#### Migrating from Unicorn
                +Set your config with the following process:
                @@ -33,6 +38,3 @@
                -* If you're migrating from unicorn though, here are some settings to start with:
                -  * Set workers to half the number of unicorn workers you're using
                -  * Set threads to 2
                -  * Enjoy 50% memory savings
                -* As you grow more confident in the thread-safety of your app, you can tune the
                -  workers down and the threads up.
                +* Use cluster mode and set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of CPU cores on the machine (minimum 2, otherwise use single mode!). If you can't add the gem, set the worker count manually to the available CPU cores.
                +* Set the number of threads to desired concurrent requests/number of workers.
                +  Puma defaults to 5, and that's a decent number.
                @@ -40 +42 @@
                -#### Ubuntu / Systemd (Systemctl) Installation
                +For most deployments, adding `concurrent-ruby` and using `workers :auto` is the right starting point.
                @@ -42 +44 @@
                -See [systemd.md](systemd.md)
                +See [`workers :auto` gotchas](../lib/puma/dsl.rb).
                @@ -44 +46 @@
                -#### Worker utilization
                +## Worker utilization
                @@ -53,3 +55,9 @@
                -there is more work to do than the process can get through. On the other hand, if
                -you have processes that sit around doing nothing, then they're just eating up
                -resources.
                +there is more work to do than the process can get through, and requests will end up with additional latency. On the other hand, if
                +you have processes that sit around doing nothing, then you're wasting resources and money.
                +
                +In general, you are making a tradeoff between:
                +
                +1. CPU and memory utilization.
                +2. Time spent queueing for a Puma worker to `accept` requests and additional latency caused by CPU contention.
                +
                +If latency is important to you, you will have to accept lower utilization, and vice versa.
                @@ -57,2 +65 @@
                -Watch your CPU utilization over time and aim for about 70% on average. 70%
                -utilization means you've got capacity still but aren't starving threads.
                +## Container/VPS sizing
                @@ -60 +67,16 @@
                -**Measuring utilization**
                +You will have to make a decision about how "big" to make each pod/VPS/server/dyno.
                +
                +**TL:DR;**: 80% of Puma apps will end up deploying "pods" of 4 workers, 5 threads each, 4 vCPU and 8GB of RAM.
                +
                +For the rest of this discussion, we'll adopt the Kubernetes term of "pods".
                +
                +Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make:
                +
                +* **Increasing worker counts decreases latency, but means you scale in bigger "chunks"**. Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                +* **Increasing thread counts will increase throughput, but also latency and memory use** Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50% of wall clock time) will lead to additional request latency and additional memory usage.
                +* **Increasing worker counts decreases memory per worker on average**. More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                +* **Low worker counts (<4) have exceptionally poor throughput**. Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing (see discussion above), which means you will have to run more pods and resources.
                +* **CPU-core-to-worker ratios should be around 1**. If running Puma with `threads > 1`, allocate 1 CPU core (see definition above!) per worker. If single threaded, allocate ~0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core. Using `workers :auto` will size workers to this guidance on most platforms.
                +* **Don't set memory limits unless necessary**. Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +
                +**Measuring utilization and queue time**
                @@ -78 +100 @@
                -      can can also be added as headers.
                +      can also be added as headers.
                @@ -102,0 +125,13 @@
                +
                +## Migrating from Unicorn
                +
                +* If you're migrating from unicorn though, here are some settings to start with:
                +  * Set workers to half the number of unicorn workers you're using
                +  * Set threads to 2
                +  * Enjoy 50% memory savings
                +* As you grow more confident in the thread-safety of your app, you can tune the
                +  workers down and the threads up.
                +
                +## Ubuntu / Systemd (Systemctl) Installation
                +
                +See [systemd.md](systemd.md)
        docs/jungle/README.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/jungle/README.md	2026-01-22 03:33:09.911766926 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/jungle/README.md	2026-01-22 03:33:09.924766849 +0000
                @@ -5 +5 @@
                -See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
                +See [/docs/systemd](https://github.com/puma/puma/blob/main/docs/systemd.md).
        docs/kubernetes.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/kubernetes.md	2026-01-22 03:33:09.911766926 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/kubernetes.md	2026-01-22 03:33:09.924766849 +0000
                @@ -5 +5 @@
                -In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some request might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                +In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some requests might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                @@ -64 +64 @@
                -There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives this request handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                +There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives and handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                @@ -72,8 +72 @@
                -With containerization, you will have to make a decision about how "big" to make each pod. Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make.
                -
                -* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                -* Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50%) will lead to additional request queueing time (latency!) and additional memory usage.
                -* More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                -* Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing, which means you will have to run more pods.
                -* If multithreaded, allocate 1 CPU per worker. If single threaded, allocate 0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core.
                -* Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +See our [deployment docs](./deployment.md) for more information about how to correctly size your pods and choose the right number of workers and threads.
        docs/plugins.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/plugins.md	2026-01-22 03:33:09.912766920 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/plugins.md	2026-01-22 03:33:09.924766849 +0000
                @@ -8 +8 @@
                -* [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb):
                +* [tmp\_restart](https://github.com/puma/puma/blob/main/lib/puma/plugin/tmp_restart.rb):
                @@ -14 +14 @@
                -Plugins are activated in a Puma configuration file (such as `config/puma.rb'`)
                +Plugins are activated in a Puma configuration file (such as `config/puma.rb`)
        docs/signals.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/signals.md	2026-01-22 03:33:09.912766920 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/signals.md	2026-01-22 03:33:09.924766849 +0000
                @@ -36,10 +36,10 @@
                -- `TTIN` increment the worker count by 1
                -- `TTOU` decrement the worker count by 1
                -- `TERM` send `TERM` to worker. The worker will attempt to finish then exit.
                -- `USR2` restart workers. This also reloads the Puma configuration file, if there is one.
                -- `USR1` restart workers in phases, a rolling restart. This will not reload the configuration file.
                -- `HUP ` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided, it will behave like `INT`
                -- `INT ` equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                -- `CHLD`
                -- `URG ` refork workers in phases from worker 0 if `fork_workers` option is enabled.
                -- `INFO` print backtraces of all puma threads
                +- `TTIN`: Increment the worker count by 1.
                +- `TTOU`: Decrement the worker count by 1.
                +- `TERM`: Send `TERM` to worker. The worker will attempt to finish then exit.
                +- `USR2`: Restart workers. This also reloads the Puma configuration file, if there is one.
                +- `USR1`: Restart workers in phases, a rolling restart. This will not reload the configuration file.
                +- `HUP`:  Reopen log files defined in `stdout_redirect` configuration parameter. If there is no `stdout_redirect` option provided, it will behave like `INT`.
                +- `INT`:  Equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                +- `CHLD`: Reap zombie child processes and wake event loop in `fork_worker` mode.
                +- `URG`:  Refork workers in phases from worker 0 if `fork_worker` option is enabled.
                +- `INFO`: Print backtraces of all Puma threads.
        docs/stats.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/stats.md	2026-01-22 03:33:09.913766914 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/stats.md	2026-01-22 03:33:09.925766843 +0000
                @@ -73 +73 @@
                -* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/master/docs/restart.md)
                +* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/main/docs/restart.md)
        docs/systemd.md
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/docs/systemd.md	2026-01-22 03:33:09.913766914 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/docs/systemd.md	2026-01-22 03:33:09.925766843 +0000
                @@ -122,2 +122,2 @@
                -folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the release folder
                -path (`/srv/projet/releases/1234/tmp/puma.sock`).
                +folder path (ex. `/srv/project/shared/tmp/puma.sock`), not the release folder
                +path (`/srv/project/releases/1234/tmp/puma.sock`).
                @@ -142 +142 @@
                -binds that's not socket activated.
                +binds that are not socket activated.
        ext/puma_http11/puma_http11.c
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:09.915766902 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:09.927766832 +0000
                @@ -11 +10,0 @@
                -#include "ext_help.h"
                @@ -17,13 +16 @@
                -#ifndef MANAGED_STRINGS
                -
                -#ifndef RSTRING_PTR
                -#define RSTRING_PTR(s) (RSTRING(s)->ptr)
                -#endif
                -#ifndef RSTRING_LEN
                -#define RSTRING_LEN(s) (RSTRING(s)->len)
                -#endif
                -
                -#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
                -#define rb_free_chars(e) /* nothing */
                -
                -#endif
                +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
                @@ -54,2 +41,2 @@
                -    rb_global_variable(var);
                -    *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                +  rb_global_variable(var);
                +  *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                @@ -80,2 +67,2 @@
                -	const size_t len;
                -	const char *name;
                +  const size_t len;
                +  const char *name;
                @@ -83 +70 @@
                -	VALUE value;
                +  VALUE value;
                @@ -94,36 +81,36 @@
                -	f("ACCEPT"),
                -	f("ACCEPT_CHARSET"),
                -	f("ACCEPT_ENCODING"),
                -	f("ACCEPT_LANGUAGE"),
                -	f("ALLOW"),
                -	f("AUTHORIZATION"),
                -	f("CACHE_CONTROL"),
                -	f("CONNECTION"),
                -	f("CONTENT_ENCODING"),
                -	fr("CONTENT_LENGTH"),
                -	fr("CONTENT_TYPE"),
                -	f("COOKIE"),
                -	f("DATE"),
                -	f("EXPECT"),
                -	f("FROM"),
                -	f("HOST"),
                -	f("IF_MATCH"),
                -	f("IF_MODIFIED_SINCE"),
                -	f("IF_NONE_MATCH"),
                -	f("IF_RANGE"),
                -	f("IF_UNMODIFIED_SINCE"),
                -	f("KEEP_ALIVE"), /* Firefox sends this */
                -	f("MAX_FORWARDS"),
                -	f("PRAGMA"),
                -	f("PROXY_AUTHORIZATION"),
                -	f("RANGE"),
                -	f("REFERER"),
                -	f("TE"),
                -	f("TRAILER"),
                -	f("TRANSFER_ENCODING"),
                -	f("UPGRADE"),
                -	f("USER_AGENT"),
                -	f("VIA"),
                -	f("X_FORWARDED_FOR"), /* common for proxies */
                -	f("X_REAL_IP"), /* common for proxies */
                -	f("WARNING")
                +  f("ACCEPT"),
                +  f("ACCEPT_CHARSET"),
                +  f("ACCEPT_ENCODING"),
                +  f("ACCEPT_LANGUAGE"),
                +  f("ALLOW"),
                +  f("AUTHORIZATION"),
                +  f("CACHE_CONTROL"),
                +  f("CONNECTION"),
                +  f("CONTENT_ENCODING"),
                +  fr("CONTENT_LENGTH"),
                +  fr("CONTENT_TYPE"),
                +  f("COOKIE"),
                +  f("DATE"),
                +  f("EXPECT"),
                +  f("FROM"),
                +  f("HOST"),
                +  f("IF_MATCH"),
                +  f("IF_MODIFIED_SINCE"),
                +  f("IF_NONE_MATCH"),
                +  f("IF_RANGE"),
                +  f("IF_UNMODIFIED_SINCE"),
                +  f("KEEP_ALIVE"), /* Firefox sends this */
                +  f("MAX_FORWARDS"),
                +  f("PRAGMA"),
                +  f("PROXY_AUTHORIZATION"),
                +  f("RANGE"),
                +  f("REFERER"),
                +  f("TE"),
                +  f("TRAILER"),
                +  f("TRANSFER_ENCODING"),
                +  f("UPGRADE"),
                +  f("USER_AGENT"),
                +  f("VIA"),
                +  f("X_FORWARDED_FOR"), /* common for proxies */
                +  f("X_REAL_IP"), /* common for proxies */
                +  f("WARNING")
                @@ -143 +130 @@
                -      cf->value = rb_str_new(cf->name, cf->len);
                +      cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
                @@ -146 +133 @@
                -      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
                +      cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
                @@ -166 +153 @@
                -void http_field(puma_parser* hp, const char *field, size_t flen,
                +static void http_field(puma_parser* hp, const char *field, size_t flen,
                @@ -189 +176 @@
                -    f = rb_str_new(hp->buf, new_size);
                +    f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
                @@ -211 +198 @@
                -void request_method(puma_parser* hp, const char *at, size_t length)
                +static void request_method(puma_parser* hp, const char *at, size_t length)
                @@ -219 +206 @@
                -void request_uri(puma_parser* hp, const char *at, size_t length)
                +static void request_uri(puma_parser* hp, const char *at, size_t length)
                @@ -229 +216 @@
                -void fragment(puma_parser* hp, const char *at, size_t length)
                +static void fragment(puma_parser* hp, const char *at, size_t length)
                @@ -239 +226 @@
                -void request_path(puma_parser* hp, const char *at, size_t length)
                +static void request_path(puma_parser* hp, const char *at, size_t length)
                @@ -249 +236 @@
                -void query_string(puma_parser* hp, const char *at, size_t length)
                +static void query_string(puma_parser* hp, const char *at, size_t length)
                @@ -259 +246 @@
                -void server_protocol(puma_parser* hp, const char *at, size_t length)
                +static void server_protocol(puma_parser* hp, const char *at, size_t length)
                @@ -268 +255 @@
                -void header_done(puma_parser* hp, const char *at, size_t length)
                +static void header_done(puma_parser* hp, const char *at, size_t length)
                @@ -274,2 +261,5 @@
                -void HttpParser_free(void *data) {
                -  TRACE();
                +static void HttpParser_mark(void *ptr) {
                +  puma_parser *hp = ptr;
                +  rb_gc_mark_movable(hp->request);
                +  rb_gc_mark_movable(hp->body);
                +}
                @@ -277,3 +267,2 @@
                -  if(data) {
                -    xfree(data);
                -  }
                +static size_t HttpParser_size(const void *ptr) {
                +  return sizeof(puma_parser);
                @@ -282 +271 @@
                -void HttpParser_mark(void *ptr) {
                +static void HttpParser_compact(void *ptr) {
                @@ -284,2 +273,2 @@
                -  if(hp->request) rb_gc_mark(hp->request);
                -  if(hp->body) rb_gc_mark(hp->body);
                +  hp->request = rb_gc_location(hp->request);
                +  hp->body = rb_gc_location(hp->body);
                @@ -288,4 +277,9 @@
                -const rb_data_type_t HttpParser_data_type = {
                -    "HttpParser",
                -    { HttpParser_mark, HttpParser_free, 0 },
                -    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
                +static const rb_data_type_t HttpParser_data_type = {
                +    .wrap_struct_name = "Puma::HttpParser",
                +    .function = {
                +      .dmark = HttpParser_mark,
                +      .dfree = RUBY_TYPED_DEFAULT_FREE,
                +      .dsize = HttpParser_size,
                +      .dcompact = HttpParser_compact,
                +    },
                +    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
                @@ -294 +288 @@
                -VALUE HttpParser_alloc(VALUE klass)
                +static VALUE HttpParser_alloc(VALUE klass)
                @@ -297 +290,0 @@
                -  TRACE();
                @@ -312,0 +306,10 @@
                +static inline puma_parser *HttpParser_unwrap(VALUE self)
                +{
                +  puma_parser *http;
                +  TypedData_Get_Struct(self, puma_parser, &HttpParser_data_type, http);
                +  if (http == NULL) {
                +    rb_raise(rb_eArgError, "%s", "NULL http_parser found");
                +  }
                +  return http;
                +}
                +
                @@ -319 +322 @@
                -VALUE HttpParser_init(VALUE self)
                +static VALUE HttpParser_init(VALUE self)
                @@ -321,2 +324 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -336 +338 @@
                -VALUE HttpParser_reset(VALUE self)
                +static VALUE HttpParser_reset(VALUE self)
                @@ -338,2 +340 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -353 +354 @@
                -VALUE HttpParser_finish(VALUE self)
                +static VALUE HttpParser_finish(VALUE self)
                @@ -355,2 +356 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -380 +380 @@
                -VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                +static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                @@ -382 +382 @@
                -  puma_parser *http = NULL;
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -387,2 +386,0 @@
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                -
                @@ -390 +388 @@
                -  dptr = rb_extract_chars(data, &dlen);
                +  RSTRING_GETMEM(data, dptr, dlen);
                @@ -393 +390,0 @@
                -    rb_free_chars(dptr);
                @@ -399 +395,0 @@
                -    rb_free_chars(dptr);
                @@ -418 +414 @@
                -VALUE HttpParser_has_error(VALUE self)
                +static VALUE HttpParser_has_error(VALUE self)
                @@ -420,2 +416 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -433 +428 @@
                -VALUE HttpParser_is_finished(VALUE self)
                +static VALUE HttpParser_is_finished(VALUE self)
                @@ -435,2 +430 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -449 +443 @@
                -VALUE HttpParser_nread(VALUE self)
                +static VALUE HttpParser_nread(VALUE self)
                @@ -451,2 +445 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -463,3 +456,2 @@
                -VALUE HttpParser_body(VALUE self) {
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +static VALUE HttpParser_body(VALUE self) {
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -474 +466 @@
                -void Init_puma_http11(void)
                +RUBY_FUNC_EXPORTED void Init_puma_http11(void)
        lib/puma/app/status.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/app/status.rb	2026-01-22 03:33:09.915766902 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/app/status.rb	2026-01-22 03:33:09.927766832 +0000
                @@ -9,0 +10 @@
                +      READ_ONLY_COMMANDS = %w[gc-stats stats].freeze
                @@ -12,0 +14 @@
                +      # @param data_only [Boolean] if true, restrict to read-only data commands
                @@ -14 +16 @@
                -      def initialize(launcher, token = nil)
                +      def initialize(launcher, token: nil, data_only: false)
                @@ -16,0 +19 @@
                +        @enabled_commands = READ_ONLY_COMMANDS if data_only
                @@ -27,0 +31,5 @@
                +        command = env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +        if @enabled_commands && !@enabled_commands.include?(command)
                +          return rack_response(404, "Command #{command.inspect} unavailable", 'text/plain')
                +        end
                +
                @@ -29 +37 @@
                -          case env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +          case command
        lib/puma/cluster.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/cluster.rb	2026-01-22 03:33:09.916766897 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/cluster.rb	2026-01-22 03:33:09.928766826 +0000
                @@ -189 +189 @@
                -        w = @workers.find { |x| x.phase != @phase }
                +        w = @workers.find { |x| x.phase < @phase }
                @@ -224 +223,0 @@
                -      server = start_server if preload?
                @@ -229 +228 @@
                -                              server: server
                +                              app: (app if preload?)
        lib/puma/cluster/worker.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:09.916766897 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:09.928766826 +0000
                @@ -17 +17 @@
                -      def initialize(index:, master:, launcher:, pipes:, server: nil)
                +      def initialize(index:, master:, launcher:, pipes:, app: nil)
                @@ -26 +26,2 @@
                -        @server = server
                +        @app = app
                +        @server = nil
                @@ -60 +61 @@
                -        server = @server ||= start_server
                +          @server = start_server
                @@ -88 +89 @@
                -                  server.begin_restart(true)
                +                  @server.begin_restart(true)
                @@ -106 +107 @@
                -          server.stop
                +          @server.stop
                @@ -118 +119 @@
                -          server_thread = server.run
                +          server_thread = @server.run
                @@ -132 +133 @@
                -                hsh = server.stats
                +                hsh = @server.stats
                @@ -138 +139 @@
                -                server.reset_max
                +                @server.reset_max
                @@ -167 +168 @@
                -                                  server: @server
                +                                  app: @app
        lib/puma/configuration.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/configuration.rb	2026-01-22 03:33:09.916766897 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/configuration.rb	2026-01-22 03:33:09.928766826 +0000
                @@ -200 +200 @@
                -    attr_reader :plugins, :events, :hooks
                +    attr_reader :plugins, :events, :hooks, :_options
                @@ -241,6 +241,2 @@
                -      workers = if env['WEB_CONCURRENCY'] == 'auto'
                -        require_processor_counter
                -        ::Concurrent.available_processor_count
                -      else
                -        env['WEB_CONCURRENCY']
                -      end
                +      workers_env = env['WEB_CONCURRENCY']
                +      workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
                @@ -252 +248 @@
                -        workers: workers && workers != "" && Integer(workers),
                +        workers: workers,
                @@ -383 +379 @@
                -        WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
                +        WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
                @@ -386,0 +383,11 @@
                +    end
                +
                +    def parse_workers(value)
                +      if value == :auto || value == 'auto'
                +        require_processor_counter
                +        Integer(::Concurrent.available_processor_count)
                +      else
                +        Integer(value)
                +      end
                +    rescue ArgumentError, TypeError
                +      raise ArgumentError, "workers must be an Integer or :auto"
        lib/puma/const.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/const.rb	2026-01-22 03:33:09.916766897 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/const.rb	2026-01-22 03:33:09.928766826 +0000
                @@ -103,2 +103,2 @@
                -    PUMA_VERSION = VERSION = "7.1.0"
                -    CODE_NAME = "Neon Witch"
                +    PUMA_VERSION = VERSION = "7.2.0"
                +    CODE_NAME = "On The Corner"
        lib/puma/dsl.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/dsl.rb	2026-01-22 03:33:09.917766891 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/dsl.rb	2026-01-22 03:33:09.929766820 +0000
                @@ -218,0 +219,2 @@
                +    # @example
                +    #   activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
                @@ -242,0 +245 @@
                +      @options[:control_data_only] = opts[:data_only] if opts[:data_only]
                @@ -669,2 +672,2 @@
                -    # How many worker processes to run.  Typically this is set to
                -    # the number of available cores.
                +    # How many worker processes to run. Typically this is set to the number of
                +    # available cores.
                @@ -673 +676,6 @@
                -    # set, otherwise 0.
                +    # set, otherwise 0. Passing +:auto+ will set the value to
                +    # +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
                +    # On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
                +    # will round down. If it rounds down to 0, Puma will run in single mode and
                +    # cluster-only hooks like +before_worker_boot+ will not execute.
                +    # If you rely on cluster-only hooks, set an explicit worker count.
                @@ -675 +683 @@
                -    # @note Cluster mode only.
                +    # A value of 0 or nil means run in single mode.
                @@ -678,0 +687 @@
                +    #   workers :auto
                @@ -683 +692 @@
                -      @options[:workers] = count.to_i
                +      @options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
                @@ -997,0 +1007 @@
                +    # @note When using `fork_worker`, this only applies to worker 0.
                @@ -1381 +1391 @@
                -    # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
                +    # @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
        lib/puma/launcher.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/launcher.rb	2026-01-22 03:33:09.918766885 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/launcher.rb	2026-01-22 03:33:09.929766820 +0000
                @@ -45 +45 @@
                -      ## Minimal initialization for a potential early restart (e.g. when pruning bundle)
                +      ## Minimal initialization before potential early restart (e.g. from bundle pruning)
                @@ -47,0 +48,2 @@
                +      # Advertise the CLI Configuration before config files are loaded
                +      Puma.cli_config = @config if defined?(Puma.cli_config)
                @@ -73,2 +75 @@
                -      # Advertise the Configuration
                -      Puma.cli_config = @config if defined?(Puma.cli_config)
                +      # Log after prune_bundler! to avoid duplicate logging if a restart occurs
        lib/puma/reactor.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/reactor.rb	2026-01-22 03:33:09.919766879 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/reactor.rb	2026-01-22 03:33:09.931766808 +0000
                @@ -78 +77,0 @@
                -      close_selector = true
                @@ -84 +82,0 @@
                -          monitor_wake_up = false
                @@ -86 +83,0 @@
                -            monitor_wake_up = true
                @@ -106,8 +103 @@
                -        # NoMethodError may be rarely raised when calling @selector.select, which
                -        # is odd.  Regardless, it may continue for thousands of calls if retried.
                -        # Also, when it raises, @selector.close also raises an error.
                -        if !monitor_wake_up && NoMethodError === e
                -          close_selector = false
                -        else
                -          retry
                -        end
                +        retry
                @@ -114,0 +105 @@
                +
                @@ -117 +108 @@
                -      @selector.close if close_selector
                +      @selector.close
        lib/puma/request.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/request.rb	2026-01-22 03:33:09.919766879 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/request.rb	2026-01-22 03:33:09.931766808 +0000
                @@ -39 +39 @@
                -    # It'll return +false+ when the connection is closed, this doesn't mean
                +    # It'll return +:close+ when the connection is closed, this doesn't mean
                @@ -41,0 +42,3 @@
                +    # It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
                +    # Which may contain additional requests.
                +    #
                @@ -48,2 +51 @@
                -    # @return [Boolean,:async]
                -    #
                +    # @return [:close, :keep_alive, :async]
                @@ -57 +59 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -170 +172 @@
                -    # @return [Boolean,:async] keep-alive status or `:async`
                +    # @return [:close, :keep_alive, :async]
                @@ -176 +178 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -247 +249 @@
                -          return keep_alive
                +          return keep_alive ? :keep_alive : :close
                @@ -273 +275 @@
                -      !shutting_down? && keep_alive
                +      !shutting_down? && keep_alive ? :keep_alive : :close
        lib/puma/runner.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/runner.rb	2026-01-22 03:33:09.919766879 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/runner.rb	2026-01-22 03:33:09.931766808 +0000
                @@ -73 +73 @@
                -      app = Puma::App::Status.new @launcher, token
                +      app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
        lib/puma/server.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/server.rb	2026-01-22 03:33:09.920766873 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/server.rb	2026-01-22 03:33:09.931766808 +0000
                @@ -302 +302 @@
                -    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).
                +    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
                @@ -504 +504 @@
                -          when false
                +          when :close
                @@ -507 +507 @@
                -          when true
                +          when :keep_alive
        lib/puma/single.rb
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/lib/puma/single.rb	2026-01-22 03:33:09.920766873 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/lib/puma/single.rb	2026-01-22 03:33:09.932766802 +0000
                @@ -52,2 +52,2 @@
                -      @server = server = start_server
                -      server_thread = server.run
                +      @server = start_server
                +      server_thread = @server.run
        tools/Dockerfile
                --- /tmp/d20260122-628-dtgj26/puma-7.1.0/tools/Dockerfile	2026-01-22 03:33:09.920766873 +0000
                +++ /tmp/d20260122-628-dtgj26/puma-7.2.0/tools/Dockerfile	2026-01-22 03:33:09.932766802 +0000
                @@ -1,0 +2,2 @@
                +# Build (MRI): docker build -f tools/Dockerfile .
                +# Build (JRuby): docker build -f tools/Dockerfile --build-arg RUBY_IMAGE=jruby:9.4 .
                @@ -3 +5,2 @@
                -FROM ruby:3.2
                +ARG RUBY_IMAGE=ruby:latest
                +FROM ${RUBY_IMAGE}
                @@ -5 +8,2 @@
                -RUN apt-get update && apt-get install -y ragel
                +# Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
                +ARG BUNDLE_FROZEN=true
                @@ -7,2 +11,6 @@
                -# throw errors if Gemfile has been modified since Gemfile.lock
                -RUN bundle config --global frozen 1
                +RUN apt-get update \
                +  && apt-get install -y --no-install-recommends ragel procps git \
                +  && rm -rf /var/lib/apt/lists/*
                +
                +# Only freeze Bundler and compile native extensions when using MRI.
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ] && [ "${BUNDLE_FROZEN}" = "true" ]; then bundle config --global frozen 1; fi
                @@ -15 +23 @@
                -RUN bundle exec rake compile
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi

@github-actions
Copy link
Contributor

gem compare --diff puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
        History.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/History.md	2026-01-22 03:33:10.787415646 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/History.md	2026-01-22 03:33:10.799415594 +0000
                @@ -0,0 +1,35 @@
                +## 7.2.0 / 2026-01-20
                +
                +* Features
                +  * Add workers `:auto` ([#3827])
                +  * Make it possible to restrict control server commands to stats ([#3787])
                +
                +* Bugfixes
                +  * Don't break if `WEB_CONCURRENCY` is set to a blank string ([#3837])
                +  * Don't share server between worker 0 and descendants on refork ([#3602])
                +  * Fix phase check race condition in `Puma::Cluster#check_workers` ([#3690])
                +  * Fix advertising of CLI config before config files are loaded ([#3823])
                +
                +* Performance
                +  * 17% faster HTTP parsing through pre-interning env keys ([#3825])
                +  * Implement `dsize` and `dcompact` functions for `Puma::HttpParser`, which makes Puma's C-extension GC-compactible ([#3828])
                +
                +* Refactor
                +  * Remove `NoMethodError` rescue in `Reactor#select_loop` ([#3831])
                +  * Various cleanups in the C extension ([#3814])
                +  * Monomorphize `handle_request` return ([#3802])
                +
                +* Docs
                +  * Change link to `docs/deployment.md` in `README.md` ([#3848])
                +  * Fix formatting for each signal description in signals.md ([#3813])
                +  * Update deployment and Kubernetes docs with Puma configuration tips ([#3807])
                +  * Rename master to main ([#3809], [#3808], [#3800])
                +  * Fix some minor typos in the docs ([#3804])
                +  * Add `GOVERNANCE.md`, `MAINTAINERS` ([#3826])
                +  * Remove Code Climate badge ([#3820])
                +  * Add @joshuay03 to the maintainer list
                +
                +* CI
                +  * Use Minitest 6 where applicable ([#3859])
                +  * Many test suite improvements and flake fixes ([#3861], [#3863], [#3860], [#3852], [#3857], [#3856], [#3845], [#3843], [#3842], [#3841], [#3822], [#3817], [#3764])
                +
                @@ -2260,0 +2296,36 @@
                +
                +[#3863]:https://github.com/puma/puma/pull/3863     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3861]:https://github.com/puma/puma/pull/3861     "PR by MSP-Greg, merged 2026-01-20"
                +[#3860]:https://github.com/puma/puma/pull/3860     "PR by MSP-Greg, merged 2026-01-16"
                +[#3859]:https://github.com/puma/puma/pull/3859     "PR by MSP-Greg, merged 2026-01-16"
                +[#3857]:https://github.com/puma/puma/pull/3857     "PR by Aaron Patterson, merged 2026-01-12"
                +[#3856]:https://github.com/puma/puma/pull/3856     "PR by MSP-Greg, merged 2026-01-12"
                +[#3852]:https://github.com/puma/puma/pull/3852     "PR by Miłosz Bieniek, merged 2026-01-14"
                +[#3848]:https://github.com/puma/puma/pull/3848     "PR by Miłosz Bieniek, merged 2025-12-27"
                +[#3845]:https://github.com/puma/puma/pull/3845     "PR by MSP-Greg, merged 2025-12-19"
                +[#3843]:https://github.com/puma/puma/pull/3843     "PR by MSP-Greg, merged 2025-12-18"
                +[#3842]:https://github.com/puma/puma/pull/3842     "PR by MSP-Greg, merged 2025-12-18"
                +[#3841]:https://github.com/puma/puma/pull/3841     "PR by MSP-Greg, merged 2025-12-18"
                +[#3837]:https://github.com/puma/puma/pull/3837     "PR by John Bachir, merged 2026-01-09"
                +[#3833]:https://github.com/puma/puma/pull/3833     "PR by Patrik Ragnarsson, merged 2025-11-25"
                +[#3831]:https://github.com/puma/puma/pull/3831     "PR by Joshua Young, merged 2025-11-25"
                +[#3828]:https://github.com/puma/puma/pull/3828     "PR by Jean Boussier, merged 2025-11-21"
                +[#3827]:https://github.com/puma/puma/pull/3827     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3826]:https://github.com/puma/puma/pull/3826     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3825]:https://github.com/puma/puma/pull/3825     "PR by Jean Boussier, merged 2025-11-19"
                +[#3823]:https://github.com/puma/puma/pull/3823     "PR by Joshua Young, merged 2025-11-18"
                +[#3822]:https://github.com/puma/puma/pull/3822     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3820]:https://github.com/puma/puma/pull/3820     "PR by Nate Berkopec, merged 2025-11-19"
                +[#3817]:https://github.com/puma/puma/pull/3817     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3814]:https://github.com/puma/puma/pull/3814     "PR by Jean Boussier, merged 2025-11-17"
                +[#3813]:https://github.com/puma/puma/pull/3813     "PR by Masafumi Koba, merged 2025-11-17"
                +[#3809]:https://github.com/puma/puma/pull/3809     "PR by Patrik Ragnarsson, merged 2025-10-26"
                +[#3808]:https://github.com/puma/puma/pull/3808     "PR by Nymuxyzo, merged 2025-10-26"
                +[#3807]:https://github.com/puma/puma/pull/3807     "PR by Nate Berkopec, merged 2025-10-28"
                +[#3804]:https://github.com/puma/puma/pull/3804     "PR by Joe Rafaniello, merged 2025-10-21"
                +[#3802]:https://github.com/puma/puma/pull/3802     "PR by Richard Schneeman, merged 2025-10-20"
                +[#3800]:https://github.com/puma/puma/pull/3800     "PR by MSP-Greg, merged 2025-10-19"
                +[#3787]:https://github.com/puma/puma/pull/3787     "PR by Stan Hu, merged 2025-10-17"
                +[#3764]:https://github.com/puma/puma/pull/3764     "PR by MSP-Greg, merged 2025-10-17"
                +[#3690]:https://github.com/puma/puma/pull/3690     "PR by Joshua Young, merged 2025-11-18"
                +[#3602]:https://github.com/puma/puma/pull/3602     "PR by Joshua Young, merged 2025-11-28"
        README.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/README.md	2026-01-22 03:33:10.787415646 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/README.md	2026-01-22 03:33:10.799415594 +0000
                @@ -7,2 +7 @@
                -[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amaster)
                -[![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
                +[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amain)
                @@ -85 +84 @@
                -Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb).
                +Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb).
                @@ -88 +87 @@
                -[test](https://github.com/puma/puma/tree/master/test/config) suite.
                +[test](https://github.com/puma/puma/tree/main/test/config) suite.
                @@ -118,0 +118,9 @@
                +When using a config file, most applications can simply set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of worker processes to the available processors:
                +
                +```ruby
                +# config/puma.rb
                +workers :auto
                +```
                +
                +See [`workers :auto` gotchas](lib/puma/dsl.rb).
                +
                @@ -121 +129 @@
                -If the `WEB_CONCURRENCY` environment variable is set to `"auto"` and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#available_processor_count-class_method).
                +If `workers` is set to `:auto`, or the `WEB_CONCURRENCY` environment variable is set to `"auto"`, and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://msp-greg.github.io/concurrent-ruby/Concurrent.html#available_processor_count-class_method).
                @@ -123 +131 @@
                -For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](https://github.com/puma/puma/blob/9282a8efa5a0c48e39c60d22ca70051a25df9f55/docs/kubernetes.md#workers-per-pod-and-other-config-issues).
                +For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](docs/deployment.md).
                @@ -229 +237 @@
                -textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
                +textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/main/lib/puma/server.rb)).
                @@ -388 +396 @@
                -Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the status app has available.
                +Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/main/lib/puma/app/status.rb) to see what the status app has available.
                @@ -420 +428 @@
                -Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to see all available options.
                +Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb) to see all available options.
        docs/deployment.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/deployment.md	2026-01-22 03:33:10.788415641 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/deployment.md	2026-01-22 03:33:10.800415589 +0000
                @@ -18,0 +19,7 @@
                +In general, use single mode only if:
                +
                +* You are using JRuby, TruffleRuby or another fully-multithreaded implementation of Ruby
                +* You are using MRI but in an environment where only 1 CPU core is available.
                +
                +Otherwise, you'll want to use cluster mode to utilize all available CPU resources.
                +
                @@ -22 +29 @@
                -Here are some tips for cluster mode:
                +## Cluster Mode Tips
                @@ -24 +31 @@
                -### MRI
                +For the purposes of Puma provisioning, "CPU cores" means:
                @@ -26,4 +33,2 @@
                -* Use cluster mode and set the number of workers to 1.5x the number of CPU cores
                -  in the machine, starting from a minimum of 2.
                -* Set the number of threads to desired concurrent requests/number of workers.
                -  Puma defaults to 5, and that's a decent number.
                +1. On ARM, the number of physical cores.
                +2. On x86, the number of logical cores, hyperthreads, or vCPUs (these words all mean the same thing).
                @@ -31 +36 @@
                -#### Migrating from Unicorn
                +Set your config with the following process:
                @@ -33,6 +38,3 @@
                -* If you're migrating from unicorn though, here are some settings to start with:
                -  * Set workers to half the number of unicorn workers you're using
                -  * Set threads to 2
                -  * Enjoy 50% memory savings
                -* As you grow more confident in the thread-safety of your app, you can tune the
                -  workers down and the threads up.
                +* Use cluster mode and set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of CPU cores on the machine (minimum 2, otherwise use single mode!). If you can't add the gem, set the worker count manually to the available CPU cores.
                +* Set the number of threads to desired concurrent requests/number of workers.
                +  Puma defaults to 5, and that's a decent number.
                @@ -40 +42 @@
                -#### Ubuntu / Systemd (Systemctl) Installation
                +For most deployments, adding `concurrent-ruby` and using `workers :auto` is the right starting point.
                @@ -42 +44 @@
                -See [systemd.md](systemd.md)
                +See [`workers :auto` gotchas](../lib/puma/dsl.rb).
                @@ -44 +46 @@
                -#### Worker utilization
                +## Worker utilization
                @@ -53,3 +55,9 @@
                -there is more work to do than the process can get through. On the other hand, if
                -you have processes that sit around doing nothing, then they're just eating up
                -resources.
                +there is more work to do than the process can get through, and requests will end up with additional latency. On the other hand, if
                +you have processes that sit around doing nothing, then you're wasting resources and money.
                +
                +In general, you are making a tradeoff between:
                +
                +1. CPU and memory utilization.
                +2. Time spent queueing for a Puma worker to `accept` requests and additional latency caused by CPU contention.
                +
                +If latency is important to you, you will have to accept lower utilization, and vice versa.
                @@ -57,2 +65 @@
                -Watch your CPU utilization over time and aim for about 70% on average. 70%
                -utilization means you've got capacity still but aren't starving threads.
                +## Container/VPS sizing
                @@ -60 +67,16 @@
                -**Measuring utilization**
                +You will have to make a decision about how "big" to make each pod/VPS/server/dyno.
                +
                +**TL:DR;**: 80% of Puma apps will end up deploying "pods" of 4 workers, 5 threads each, 4 vCPU and 8GB of RAM.
                +
                +For the rest of this discussion, we'll adopt the Kubernetes term of "pods".
                +
                +Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make:
                +
                +* **Increasing worker counts decreases latency, but means you scale in bigger "chunks"**. Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                +* **Increasing thread counts will increase throughput, but also latency and memory use** Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50% of wall clock time) will lead to additional request latency and additional memory usage.
                +* **Increasing worker counts decreases memory per worker on average**. More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                +* **Low worker counts (<4) have exceptionally poor throughput**. Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing (see discussion above), which means you will have to run more pods and resources.
                +* **CPU-core-to-worker ratios should be around 1**. If running Puma with `threads > 1`, allocate 1 CPU core (see definition above!) per worker. If single threaded, allocate ~0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core. Using `workers :auto` will size workers to this guidance on most platforms.
                +* **Don't set memory limits unless necessary**. Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +
                +**Measuring utilization and queue time**
                @@ -78 +100 @@
                -      can can also be added as headers.
                +      can also be added as headers.
                @@ -102,0 +125,13 @@
                +
                +## Migrating from Unicorn
                +
                +* If you're migrating from unicorn though, here are some settings to start with:
                +  * Set workers to half the number of unicorn workers you're using
                +  * Set threads to 2
                +  * Enjoy 50% memory savings
                +* As you grow more confident in the thread-safety of your app, you can tune the
                +  workers down and the threads up.
                +
                +## Ubuntu / Systemd (Systemctl) Installation
                +
                +See [systemd.md](systemd.md)
        docs/jungle/README.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/jungle/README.md	2026-01-22 03:33:10.789415637 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/jungle/README.md	2026-01-22 03:33:10.801415585 +0000
                @@ -5 +5 @@
                -See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
                +See [/docs/systemd](https://github.com/puma/puma/blob/main/docs/systemd.md).
        docs/kubernetes.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/kubernetes.md	2026-01-22 03:33:10.789415637 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/kubernetes.md	2026-01-22 03:33:10.802415581 +0000
                @@ -5 +5 @@
                -In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some request might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                +In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some requests might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                @@ -64 +64 @@
                -There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives this request handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                +There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives and handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                @@ -72,8 +72 @@
                -With containerization, you will have to make a decision about how "big" to make each pod. Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make.
                -
                -* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                -* Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50%) will lead to additional request queueing time (latency!) and additional memory usage.
                -* More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                -* Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing, which means you will have to run more pods.
                -* If multithreaded, allocate 1 CPU per worker. If single threaded, allocate 0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core.
                -* Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +See our [deployment docs](./deployment.md) for more information about how to correctly size your pods and choose the right number of workers and threads.
        docs/plugins.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/plugins.md	2026-01-22 03:33:10.789415637 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/plugins.md	2026-01-22 03:33:10.802415581 +0000
                @@ -8 +8 @@
                -* [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb):
                +* [tmp\_restart](https://github.com/puma/puma/blob/main/lib/puma/plugin/tmp_restart.rb):
                @@ -14 +14 @@
                -Plugins are activated in a Puma configuration file (such as `config/puma.rb'`)
                +Plugins are activated in a Puma configuration file (such as `config/puma.rb`)
        docs/signals.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/signals.md	2026-01-22 03:33:10.790415633 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/signals.md	2026-01-22 03:33:10.802415581 +0000
                @@ -36,10 +36,10 @@
                -- `TTIN` increment the worker count by 1
                -- `TTOU` decrement the worker count by 1
                -- `TERM` send `TERM` to worker. The worker will attempt to finish then exit.
                -- `USR2` restart workers. This also reloads the Puma configuration file, if there is one.
                -- `USR1` restart workers in phases, a rolling restart. This will not reload the configuration file.
                -- `HUP ` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided, it will behave like `INT`
                -- `INT ` equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                -- `CHLD`
                -- `URG ` refork workers in phases from worker 0 if `fork_workers` option is enabled.
                -- `INFO` print backtraces of all puma threads
                +- `TTIN`: Increment the worker count by 1.
                +- `TTOU`: Decrement the worker count by 1.
                +- `TERM`: Send `TERM` to worker. The worker will attempt to finish then exit.
                +- `USR2`: Restart workers. This also reloads the Puma configuration file, if there is one.
                +- `USR1`: Restart workers in phases, a rolling restart. This will not reload the configuration file.
                +- `HUP`:  Reopen log files defined in `stdout_redirect` configuration parameter. If there is no `stdout_redirect` option provided, it will behave like `INT`.
                +- `INT`:  Equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                +- `CHLD`: Reap zombie child processes and wake event loop in `fork_worker` mode.
                +- `URG`:  Refork workers in phases from worker 0 if `fork_worker` option is enabled.
                +- `INFO`: Print backtraces of all Puma threads.
        docs/stats.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/stats.md	2026-01-22 03:33:10.790415633 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/stats.md	2026-01-22 03:33:10.802415581 +0000
                @@ -73 +73 @@
                -* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/master/docs/restart.md)
                +* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/main/docs/restart.md)
        docs/systemd.md
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/docs/systemd.md	2026-01-22 03:33:10.790415633 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/docs/systemd.md	2026-01-22 03:33:10.802415581 +0000
                @@ -122,2 +122,2 @@
                -folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the release folder
                -path (`/srv/projet/releases/1234/tmp/puma.sock`).
                +folder path (ex. `/srv/project/shared/tmp/puma.sock`), not the release folder
                +path (`/srv/project/releases/1234/tmp/puma.sock`).
                @@ -142 +142 @@
                -binds that's not socket activated.
                +binds that are not socket activated.
        ext/puma_http11/puma_http11.c
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:10.792415624 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:10.804415572 +0000
                @@ -11 +10,0 @@
                -#include "ext_help.h"
                @@ -17,13 +16 @@
                -#ifndef MANAGED_STRINGS
                -
                -#ifndef RSTRING_PTR
                -#define RSTRING_PTR(s) (RSTRING(s)->ptr)
                -#endif
                -#ifndef RSTRING_LEN
                -#define RSTRING_LEN(s) (RSTRING(s)->len)
                -#endif
                -
                -#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
                -#define rb_free_chars(e) /* nothing */
                -
                -#endif
                +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
                @@ -54,2 +41,2 @@
                -    rb_global_variable(var);
                -    *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                +  rb_global_variable(var);
                +  *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                @@ -80,2 +67,2 @@
                -	const size_t len;
                -	const char *name;
                +  const size_t len;
                +  const char *name;
                @@ -83 +70 @@
                -	VALUE value;
                +  VALUE value;
                @@ -94,36 +81,36 @@
                -	f("ACCEPT"),
                -	f("ACCEPT_CHARSET"),
                -	f("ACCEPT_ENCODING"),
                -	f("ACCEPT_LANGUAGE"),
                -	f("ALLOW"),
                -	f("AUTHORIZATION"),
                -	f("CACHE_CONTROL"),
                -	f("CONNECTION"),
                -	f("CONTENT_ENCODING"),
                -	fr("CONTENT_LENGTH"),
                -	fr("CONTENT_TYPE"),
                -	f("COOKIE"),
                -	f("DATE"),
                -	f("EXPECT"),
                -	f("FROM"),
                -	f("HOST"),
                -	f("IF_MATCH"),
                -	f("IF_MODIFIED_SINCE"),
                -	f("IF_NONE_MATCH"),
                -	f("IF_RANGE"),
                -	f("IF_UNMODIFIED_SINCE"),
                -	f("KEEP_ALIVE"), /* Firefox sends this */
                -	f("MAX_FORWARDS"),
                -	f("PRAGMA"),
                -	f("PROXY_AUTHORIZATION"),
                -	f("RANGE"),
                -	f("REFERER"),
                -	f("TE"),
                -	f("TRAILER"),
                -	f("TRANSFER_ENCODING"),
                -	f("UPGRADE"),
                -	f("USER_AGENT"),
                -	f("VIA"),
                -	f("X_FORWARDED_FOR"), /* common for proxies */
                -	f("X_REAL_IP"), /* common for proxies */
                -	f("WARNING")
                +  f("ACCEPT"),
                +  f("ACCEPT_CHARSET"),
                +  f("ACCEPT_ENCODING"),
                +  f("ACCEPT_LANGUAGE"),
                +  f("ALLOW"),
                +  f("AUTHORIZATION"),
                +  f("CACHE_CONTROL"),
                +  f("CONNECTION"),
                +  f("CONTENT_ENCODING"),
                +  fr("CONTENT_LENGTH"),
                +  fr("CONTENT_TYPE"),
                +  f("COOKIE"),
                +  f("DATE"),
                +  f("EXPECT"),
                +  f("FROM"),
                +  f("HOST"),
                +  f("IF_MATCH"),
                +  f("IF_MODIFIED_SINCE"),
                +  f("IF_NONE_MATCH"),
                +  f("IF_RANGE"),
                +  f("IF_UNMODIFIED_SINCE"),
                +  f("KEEP_ALIVE"), /* Firefox sends this */
                +  f("MAX_FORWARDS"),
                +  f("PRAGMA"),
                +  f("PROXY_AUTHORIZATION"),
                +  f("RANGE"),
                +  f("REFERER"),
                +  f("TE"),
                +  f("TRAILER"),
                +  f("TRANSFER_ENCODING"),
                +  f("UPGRADE"),
                +  f("USER_AGENT"),
                +  f("VIA"),
                +  f("X_FORWARDED_FOR"), /* common for proxies */
                +  f("X_REAL_IP"), /* common for proxies */
                +  f("WARNING")
                @@ -143 +130 @@
                -      cf->value = rb_str_new(cf->name, cf->len);
                +      cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
                @@ -146 +133 @@
                -      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
                +      cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
                @@ -166 +153 @@
                -void http_field(puma_parser* hp, const char *field, size_t flen,
                +static void http_field(puma_parser* hp, const char *field, size_t flen,
                @@ -189 +176 @@
                -    f = rb_str_new(hp->buf, new_size);
                +    f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
                @@ -211 +198 @@
                -void request_method(puma_parser* hp, const char *at, size_t length)
                +static void request_method(puma_parser* hp, const char *at, size_t length)
                @@ -219 +206 @@
                -void request_uri(puma_parser* hp, const char *at, size_t length)
                +static void request_uri(puma_parser* hp, const char *at, size_t length)
                @@ -229 +216 @@
                -void fragment(puma_parser* hp, const char *at, size_t length)
                +static void fragment(puma_parser* hp, const char *at, size_t length)
                @@ -239 +226 @@
                -void request_path(puma_parser* hp, const char *at, size_t length)
                +static void request_path(puma_parser* hp, const char *at, size_t length)
                @@ -249 +236 @@
                -void query_string(puma_parser* hp, const char *at, size_t length)
                +static void query_string(puma_parser* hp, const char *at, size_t length)
                @@ -259 +246 @@
                -void server_protocol(puma_parser* hp, const char *at, size_t length)
                +static void server_protocol(puma_parser* hp, const char *at, size_t length)
                @@ -268 +255 @@
                -void header_done(puma_parser* hp, const char *at, size_t length)
                +static void header_done(puma_parser* hp, const char *at, size_t length)
                @@ -274,2 +261,5 @@
                -void HttpParser_free(void *data) {
                -  TRACE();
                +static void HttpParser_mark(void *ptr) {
                +  puma_parser *hp = ptr;
                +  rb_gc_mark_movable(hp->request);
                +  rb_gc_mark_movable(hp->body);
                +}
                @@ -277,3 +267,2 @@
                -  if(data) {
                -    xfree(data);
                -  }
                +static size_t HttpParser_size(const void *ptr) {
                +  return sizeof(puma_parser);
                @@ -282 +271 @@
                -void HttpParser_mark(void *ptr) {
                +static void HttpParser_compact(void *ptr) {
                @@ -284,2 +273,2 @@
                -  if(hp->request) rb_gc_mark(hp->request);
                -  if(hp->body) rb_gc_mark(hp->body);
                +  hp->request = rb_gc_location(hp->request);
                +  hp->body = rb_gc_location(hp->body);
                @@ -288,4 +277,9 @@
                -const rb_data_type_t HttpParser_data_type = {
                -    "HttpParser",
                -    { HttpParser_mark, HttpParser_free, 0 },
                -    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
                +static const rb_data_type_t HttpParser_data_type = {
                +    .wrap_struct_name = "Puma::HttpParser",
                +    .function = {
                +      .dmark = HttpParser_mark,
                +      .dfree = RUBY_TYPED_DEFAULT_FREE,
                +      .dsize = HttpParser_size,
                +      .dcompact = HttpParser_compact,
                +    },
                +    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
                @@ -294 +288 @@
                -VALUE HttpParser_alloc(VALUE klass)
                +static VALUE HttpParser_alloc(VALUE klass)
                @@ -297 +290,0 @@
                -  TRACE();
                @@ -312,0 +306,10 @@
                +static inline puma_parser *HttpParser_unwrap(VALUE self)
                +{
                +  puma_parser *http;
                +  TypedData_Get_Struct(self, puma_parser, &HttpParser_data_type, http);
                +  if (http == NULL) {
                +    rb_raise(rb_eArgError, "%s", "NULL http_parser found");
                +  }
                +  return http;
                +}
                +
                @@ -319 +322 @@
                -VALUE HttpParser_init(VALUE self)
                +static VALUE HttpParser_init(VALUE self)
                @@ -321,2 +324 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -336 +338 @@
                -VALUE HttpParser_reset(VALUE self)
                +static VALUE HttpParser_reset(VALUE self)
                @@ -338,2 +340 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -353 +354 @@
                -VALUE HttpParser_finish(VALUE self)
                +static VALUE HttpParser_finish(VALUE self)
                @@ -355,2 +356 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -380 +380 @@
                -VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                +static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                @@ -382 +382 @@
                -  puma_parser *http = NULL;
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -387,2 +386,0 @@
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                -
                @@ -390 +388 @@
                -  dptr = rb_extract_chars(data, &dlen);
                +  RSTRING_GETMEM(data, dptr, dlen);
                @@ -393 +390,0 @@
                -    rb_free_chars(dptr);
                @@ -399 +395,0 @@
                -    rb_free_chars(dptr);
                @@ -418 +414 @@
                -VALUE HttpParser_has_error(VALUE self)
                +static VALUE HttpParser_has_error(VALUE self)
                @@ -420,2 +416 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -433 +428 @@
                -VALUE HttpParser_is_finished(VALUE self)
                +static VALUE HttpParser_is_finished(VALUE self)
                @@ -435,2 +430 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -449 +443 @@
                -VALUE HttpParser_nread(VALUE self)
                +static VALUE HttpParser_nread(VALUE self)
                @@ -451,2 +445 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -463,3 +456,2 @@
                -VALUE HttpParser_body(VALUE self) {
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +static VALUE HttpParser_body(VALUE self) {
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -474 +466 @@
                -void Init_puma_http11(void)
                +RUBY_FUNC_EXPORTED void Init_puma_http11(void)
        lib/puma/app/status.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/app/status.rb	2026-01-22 03:33:10.793415620 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/app/status.rb	2026-01-22 03:33:10.804415572 +0000
                @@ -9,0 +10 @@
                +      READ_ONLY_COMMANDS = %w[gc-stats stats].freeze
                @@ -12,0 +14 @@
                +      # @param data_only [Boolean] if true, restrict to read-only data commands
                @@ -14 +16 @@
                -      def initialize(launcher, token = nil)
                +      def initialize(launcher, token: nil, data_only: false)
                @@ -16,0 +19 @@
                +        @enabled_commands = READ_ONLY_COMMANDS if data_only
                @@ -27,0 +31,5 @@
                +        command = env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +        if @enabled_commands && !@enabled_commands.include?(command)
                +          return rack_response(404, "Command #{command.inspect} unavailable", 'text/plain')
                +        end
                +
                @@ -29 +37 @@
                -          case env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +          case command
        lib/puma/cluster.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/cluster.rb	2026-01-22 03:33:10.793415620 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/cluster.rb	2026-01-22 03:33:10.805415568 +0000
                @@ -189 +189 @@
                -        w = @workers.find { |x| x.phase != @phase }
                +        w = @workers.find { |x| x.phase < @phase }
                @@ -224 +223,0 @@
                -      server = start_server if preload?
                @@ -229 +228 @@
                -                              server: server
                +                              app: (app if preload?)
        lib/puma/cluster/worker.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:10.794415615 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:10.805415568 +0000
                @@ -17 +17 @@
                -      def initialize(index:, master:, launcher:, pipes:, server: nil)
                +      def initialize(index:, master:, launcher:, pipes:, app: nil)
                @@ -26 +26,2 @@
                -        @server = server
                +        @app = app
                +        @server = nil
                @@ -60 +61 @@
                -        server = @server ||= start_server
                +          @server = start_server
                @@ -88 +89 @@
                -                  server.begin_restart(true)
                +                  @server.begin_restart(true)
                @@ -106 +107 @@
                -          server.stop
                +          @server.stop
                @@ -118 +119 @@
                -          server_thread = server.run
                +          server_thread = @server.run
                @@ -132 +133 @@
                -                hsh = server.stats
                +                hsh = @server.stats
                @@ -138 +139 @@
                -                server.reset_max
                +                @server.reset_max
                @@ -167 +168 @@
                -                                  server: @server
                +                                  app: @app
        lib/puma/configuration.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/configuration.rb	2026-01-22 03:33:10.794415615 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/configuration.rb	2026-01-22 03:33:10.806415563 +0000
                @@ -200 +200 @@
                -    attr_reader :plugins, :events, :hooks
                +    attr_reader :plugins, :events, :hooks, :_options
                @@ -241,6 +241,2 @@
                -      workers = if env['WEB_CONCURRENCY'] == 'auto'
                -        require_processor_counter
                -        ::Concurrent.available_processor_count
                -      else
                -        env['WEB_CONCURRENCY']
                -      end
                +      workers_env = env['WEB_CONCURRENCY']
                +      workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
                @@ -252 +248 @@
                -        workers: workers && workers != "" && Integer(workers),
                +        workers: workers,
                @@ -383 +379 @@
                -        WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
                +        WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
                @@ -386,0 +383,11 @@
                +    end
                +
                +    def parse_workers(value)
                +      if value == :auto || value == 'auto'
                +        require_processor_counter
                +        Integer(::Concurrent.available_processor_count)
                +      else
                +        Integer(value)
                +      end
                +    rescue ArgumentError, TypeError
                +      raise ArgumentError, "workers must be an Integer or :auto"
        lib/puma/const.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/const.rb	2026-01-22 03:33:10.794415615 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/const.rb	2026-01-22 03:33:10.806415563 +0000
                @@ -103,2 +103,2 @@
                -    PUMA_VERSION = VERSION = "7.1.0"
                -    CODE_NAME = "Neon Witch"
                +    PUMA_VERSION = VERSION = "7.2.0"
                +    CODE_NAME = "On The Corner"
        lib/puma/dsl.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/dsl.rb	2026-01-22 03:33:10.795415611 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/dsl.rb	2026-01-22 03:33:10.807415559 +0000
                @@ -218,0 +219,2 @@
                +    # @example
                +    #   activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
                @@ -242,0 +245 @@
                +      @options[:control_data_only] = opts[:data_only] if opts[:data_only]
                @@ -669,2 +672,2 @@
                -    # How many worker processes to run.  Typically this is set to
                -    # the number of available cores.
                +    # How many worker processes to run. Typically this is set to the number of
                +    # available cores.
                @@ -673 +676,6 @@
                -    # set, otherwise 0.
                +    # set, otherwise 0. Passing +:auto+ will set the value to
                +    # +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
                +    # On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
                +    # will round down. If it rounds down to 0, Puma will run in single mode and
                +    # cluster-only hooks like +before_worker_boot+ will not execute.
                +    # If you rely on cluster-only hooks, set an explicit worker count.
                @@ -675 +683 @@
                -    # @note Cluster mode only.
                +    # A value of 0 or nil means run in single mode.
                @@ -678,0 +687 @@
                +    #   workers :auto
                @@ -683 +692 @@
                -      @options[:workers] = count.to_i
                +      @options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
                @@ -997,0 +1007 @@
                +    # @note When using `fork_worker`, this only applies to worker 0.
                @@ -1381 +1391 @@
                -    # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
                +    # @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
        lib/puma/launcher.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/launcher.rb	2026-01-22 03:33:10.795415611 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/launcher.rb	2026-01-22 03:33:10.807415559 +0000
                @@ -45 +45 @@
                -      ## Minimal initialization for a potential early restart (e.g. when pruning bundle)
                +      ## Minimal initialization before potential early restart (e.g. from bundle pruning)
                @@ -47,0 +48,2 @@
                +      # Advertise the CLI Configuration before config files are loaded
                +      Puma.cli_config = @config if defined?(Puma.cli_config)
                @@ -73,2 +75 @@
                -      # Advertise the Configuration
                -      Puma.cli_config = @config if defined?(Puma.cli_config)
                +      # Log after prune_bundler! to avoid duplicate logging if a restart occurs
        lib/puma/reactor.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/reactor.rb	2026-01-22 03:33:10.797415602 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/reactor.rb	2026-01-22 03:33:10.809415550 +0000
                @@ -78 +77,0 @@
                -      close_selector = true
                @@ -84 +82,0 @@
                -          monitor_wake_up = false
                @@ -86 +83,0 @@
                -            monitor_wake_up = true
                @@ -106,8 +103 @@
                -        # NoMethodError may be rarely raised when calling @selector.select, which
                -        # is odd.  Regardless, it may continue for thousands of calls if retried.
                -        # Also, when it raises, @selector.close also raises an error.
                -        if !monitor_wake_up && NoMethodError === e
                -          close_selector = false
                -        else
                -          retry
                -        end
                +        retry
                @@ -114,0 +105 @@
                +
                @@ -117 +108 @@
                -      @selector.close if close_selector
                +      @selector.close
        lib/puma/request.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/request.rb	2026-01-22 03:33:10.797415602 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/request.rb	2026-01-22 03:33:10.809415550 +0000
                @@ -39 +39 @@
                -    # It'll return +false+ when the connection is closed, this doesn't mean
                +    # It'll return +:close+ when the connection is closed, this doesn't mean
                @@ -41,0 +42,3 @@
                +    # It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
                +    # Which may contain additional requests.
                +    #
                @@ -48,2 +51 @@
                -    # @return [Boolean,:async]
                -    #
                +    # @return [:close, :keep_alive, :async]
                @@ -57 +59 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -170 +172 @@
                -    # @return [Boolean,:async] keep-alive status or `:async`
                +    # @return [:close, :keep_alive, :async]
                @@ -176 +178 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -247 +249 @@
                -          return keep_alive
                +          return keep_alive ? :keep_alive : :close
                @@ -273 +275 @@
                -      !shutting_down? && keep_alive
                +      !shutting_down? && keep_alive ? :keep_alive : :close
        lib/puma/runner.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/runner.rb	2026-01-22 03:33:10.797415602 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/runner.rb	2026-01-22 03:33:10.809415550 +0000
                @@ -73 +73 @@
                -      app = Puma::App::Status.new @launcher, token
                +      app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
        lib/puma/server.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/server.rb	2026-01-22 03:33:10.797415602 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/server.rb	2026-01-22 03:33:10.809415550 +0000
                @@ -302 +302 @@
                -    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).
                +    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
                @@ -504 +504 @@
                -          when false
                +          when :close
                @@ -507 +507 @@
                -          when true
                +          when :keep_alive
        lib/puma/single.rb
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/lib/puma/single.rb	2026-01-22 03:33:10.797415602 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/lib/puma/single.rb	2026-01-22 03:33:10.809415550 +0000
                @@ -52,2 +52,2 @@
                -      @server = server = start_server
                -      server_thread = server.run
                +      @server = start_server
                +      server_thread = @server.run
        tools/Dockerfile
                --- /tmp/d20260122-781-vqo30n/puma-7.1.0/tools/Dockerfile	2026-01-22 03:33:10.798415598 +0000
                +++ /tmp/d20260122-781-vqo30n/puma-7.2.0/tools/Dockerfile	2026-01-22 03:33:10.810415546 +0000
                @@ -1,0 +2,2 @@
                +# Build (MRI): docker build -f tools/Dockerfile .
                +# Build (JRuby): docker build -f tools/Dockerfile --build-arg RUBY_IMAGE=jruby:9.4 .
                @@ -3 +5,2 @@
                -FROM ruby:3.2
                +ARG RUBY_IMAGE=ruby:latest
                +FROM ${RUBY_IMAGE}
                @@ -5 +8,2 @@
                -RUN apt-get update && apt-get install -y ragel
                +# Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
                +ARG BUNDLE_FROZEN=true
                @@ -7,2 +11,6 @@
                -# throw errors if Gemfile has been modified since Gemfile.lock
                -RUN bundle config --global frozen 1
                +RUN apt-get update \
                +  && apt-get install -y --no-install-recommends ragel procps git \
                +  && rm -rf /var/lib/apt/lists/*
                +
                +# Only freeze Bundler and compile native extensions when using MRI.
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ] && [ "${BUNDLE_FROZEN}" = "true" ]; then bundle config --global frozen 1; fi
                @@ -15 +23 @@
                -RUN bundle exec rake compile
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi

@github-actions
Copy link
Contributor

gem compare --diff puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
        History.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/History.md	2026-01-22 03:33:12.099556498 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/History.md	2026-01-22 03:33:12.111556393 +0000
                @@ -0,0 +1,35 @@
                +## 7.2.0 / 2026-01-20
                +
                +* Features
                +  * Add workers `:auto` ([#3827])
                +  * Make it possible to restrict control server commands to stats ([#3787])
                +
                +* Bugfixes
                +  * Don't break if `WEB_CONCURRENCY` is set to a blank string ([#3837])
                +  * Don't share server between worker 0 and descendants on refork ([#3602])
                +  * Fix phase check race condition in `Puma::Cluster#check_workers` ([#3690])
                +  * Fix advertising of CLI config before config files are loaded ([#3823])
                +
                +* Performance
                +  * 17% faster HTTP parsing through pre-interning env keys ([#3825])
                +  * Implement `dsize` and `dcompact` functions for `Puma::HttpParser`, which makes Puma's C-extension GC-compactible ([#3828])
                +
                +* Refactor
                +  * Remove `NoMethodError` rescue in `Reactor#select_loop` ([#3831])
                +  * Various cleanups in the C extension ([#3814])
                +  * Monomorphize `handle_request` return ([#3802])
                +
                +* Docs
                +  * Change link to `docs/deployment.md` in `README.md` ([#3848])
                +  * Fix formatting for each signal description in signals.md ([#3813])
                +  * Update deployment and Kubernetes docs with Puma configuration tips ([#3807])
                +  * Rename master to main ([#3809], [#3808], [#3800])
                +  * Fix some minor typos in the docs ([#3804])
                +  * Add `GOVERNANCE.md`, `MAINTAINERS` ([#3826])
                +  * Remove Code Climate badge ([#3820])
                +  * Add @joshuay03 to the maintainer list
                +
                +* CI
                +  * Use Minitest 6 where applicable ([#3859])
                +  * Many test suite improvements and flake fixes ([#3861], [#3863], [#3860], [#3852], [#3857], [#3856], [#3845], [#3843], [#3842], [#3841], [#3822], [#3817], [#3764])
                +
                @@ -2260,0 +2296,36 @@
                +
                +[#3863]:https://github.com/puma/puma/pull/3863     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3861]:https://github.com/puma/puma/pull/3861     "PR by MSP-Greg, merged 2026-01-20"
                +[#3860]:https://github.com/puma/puma/pull/3860     "PR by MSP-Greg, merged 2026-01-16"
                +[#3859]:https://github.com/puma/puma/pull/3859     "PR by MSP-Greg, merged 2026-01-16"
                +[#3857]:https://github.com/puma/puma/pull/3857     "PR by Aaron Patterson, merged 2026-01-12"
                +[#3856]:https://github.com/puma/puma/pull/3856     "PR by MSP-Greg, merged 2026-01-12"
                +[#3852]:https://github.com/puma/puma/pull/3852     "PR by Miłosz Bieniek, merged 2026-01-14"
                +[#3848]:https://github.com/puma/puma/pull/3848     "PR by Miłosz Bieniek, merged 2025-12-27"
                +[#3845]:https://github.com/puma/puma/pull/3845     "PR by MSP-Greg, merged 2025-12-19"
                +[#3843]:https://github.com/puma/puma/pull/3843     "PR by MSP-Greg, merged 2025-12-18"
                +[#3842]:https://github.com/puma/puma/pull/3842     "PR by MSP-Greg, merged 2025-12-18"
                +[#3841]:https://github.com/puma/puma/pull/3841     "PR by MSP-Greg, merged 2025-12-18"
                +[#3837]:https://github.com/puma/puma/pull/3837     "PR by John Bachir, merged 2026-01-09"
                +[#3833]:https://github.com/puma/puma/pull/3833     "PR by Patrik Ragnarsson, merged 2025-11-25"
                +[#3831]:https://github.com/puma/puma/pull/3831     "PR by Joshua Young, merged 2025-11-25"
                +[#3828]:https://github.com/puma/puma/pull/3828     "PR by Jean Boussier, merged 2025-11-21"
                +[#3827]:https://github.com/puma/puma/pull/3827     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3826]:https://github.com/puma/puma/pull/3826     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3825]:https://github.com/puma/puma/pull/3825     "PR by Jean Boussier, merged 2025-11-19"
                +[#3823]:https://github.com/puma/puma/pull/3823     "PR by Joshua Young, merged 2025-11-18"
                +[#3822]:https://github.com/puma/puma/pull/3822     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3820]:https://github.com/puma/puma/pull/3820     "PR by Nate Berkopec, merged 2025-11-19"
                +[#3817]:https://github.com/puma/puma/pull/3817     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3814]:https://github.com/puma/puma/pull/3814     "PR by Jean Boussier, merged 2025-11-17"
                +[#3813]:https://github.com/puma/puma/pull/3813     "PR by Masafumi Koba, merged 2025-11-17"
                +[#3809]:https://github.com/puma/puma/pull/3809     "PR by Patrik Ragnarsson, merged 2025-10-26"
                +[#3808]:https://github.com/puma/puma/pull/3808     "PR by Nymuxyzo, merged 2025-10-26"
                +[#3807]:https://github.com/puma/puma/pull/3807     "PR by Nate Berkopec, merged 2025-10-28"
                +[#3804]:https://github.com/puma/puma/pull/3804     "PR by Joe Rafaniello, merged 2025-10-21"
                +[#3802]:https://github.com/puma/puma/pull/3802     "PR by Richard Schneeman, merged 2025-10-20"
                +[#3800]:https://github.com/puma/puma/pull/3800     "PR by MSP-Greg, merged 2025-10-19"
                +[#3787]:https://github.com/puma/puma/pull/3787     "PR by Stan Hu, merged 2025-10-17"
                +[#3764]:https://github.com/puma/puma/pull/3764     "PR by MSP-Greg, merged 2025-10-17"
                +[#3690]:https://github.com/puma/puma/pull/3690     "PR by Joshua Young, merged 2025-11-18"
                +[#3602]:https://github.com/puma/puma/pull/3602     "PR by Joshua Young, merged 2025-11-28"
        README.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/README.md	2026-01-22 03:33:12.099556498 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/README.md	2026-01-22 03:33:12.112556384 +0000
                @@ -7,2 +7 @@
                -[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amaster)
                -[![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
                +[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amain)
                @@ -85 +84 @@
                -Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb).
                +Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb).
                @@ -88 +87 @@
                -[test](https://github.com/puma/puma/tree/master/test/config) suite.
                +[test](https://github.com/puma/puma/tree/main/test/config) suite.
                @@ -118,0 +118,9 @@
                +When using a config file, most applications can simply set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of worker processes to the available processors:
                +
                +```ruby
                +# config/puma.rb
                +workers :auto
                +```
                +
                +See [`workers :auto` gotchas](lib/puma/dsl.rb).
                +
                @@ -121 +129 @@
                -If the `WEB_CONCURRENCY` environment variable is set to `"auto"` and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#available_processor_count-class_method).
                +If `workers` is set to `:auto`, or the `WEB_CONCURRENCY` environment variable is set to `"auto"`, and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://msp-greg.github.io/concurrent-ruby/Concurrent.html#available_processor_count-class_method).
                @@ -123 +131 @@
                -For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](https://github.com/puma/puma/blob/9282a8efa5a0c48e39c60d22ca70051a25df9f55/docs/kubernetes.md#workers-per-pod-and-other-config-issues).
                +For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](docs/deployment.md).
                @@ -229 +237 @@
                -textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
                +textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/main/lib/puma/server.rb)).
                @@ -388 +396 @@
                -Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the status app has available.
                +Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/main/lib/puma/app/status.rb) to see what the status app has available.
                @@ -420 +428 @@
                -Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to see all available options.
                +Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb) to see all available options.
        docs/deployment.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/deployment.md	2026-01-22 03:33:12.100556489 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/deployment.md	2026-01-22 03:33:12.112556384 +0000
                @@ -18,0 +19,7 @@
                +In general, use single mode only if:
                +
                +* You are using JRuby, TruffleRuby or another fully-multithreaded implementation of Ruby
                +* You are using MRI but in an environment where only 1 CPU core is available.
                +
                +Otherwise, you'll want to use cluster mode to utilize all available CPU resources.
                +
                @@ -22 +29 @@
                -Here are some tips for cluster mode:
                +## Cluster Mode Tips
                @@ -24 +31 @@
                -### MRI
                +For the purposes of Puma provisioning, "CPU cores" means:
                @@ -26,4 +33,2 @@
                -* Use cluster mode and set the number of workers to 1.5x the number of CPU cores
                -  in the machine, starting from a minimum of 2.
                -* Set the number of threads to desired concurrent requests/number of workers.
                -  Puma defaults to 5, and that's a decent number.
                +1. On ARM, the number of physical cores.
                +2. On x86, the number of logical cores, hyperthreads, or vCPUs (these words all mean the same thing).
                @@ -31 +36 @@
                -#### Migrating from Unicorn
                +Set your config with the following process:
                @@ -33,6 +38,3 @@
                -* If you're migrating from unicorn though, here are some settings to start with:
                -  * Set workers to half the number of unicorn workers you're using
                -  * Set threads to 2
                -  * Enjoy 50% memory savings
                -* As you grow more confident in the thread-safety of your app, you can tune the
                -  workers down and the threads up.
                +* Use cluster mode and set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of CPU cores on the machine (minimum 2, otherwise use single mode!). If you can't add the gem, set the worker count manually to the available CPU cores.
                +* Set the number of threads to desired concurrent requests/number of workers.
                +  Puma defaults to 5, and that's a decent number.
                @@ -40 +42 @@
                -#### Ubuntu / Systemd (Systemctl) Installation
                +For most deployments, adding `concurrent-ruby` and using `workers :auto` is the right starting point.
                @@ -42 +44 @@
                -See [systemd.md](systemd.md)
                +See [`workers :auto` gotchas](../lib/puma/dsl.rb).
                @@ -44 +46 @@
                -#### Worker utilization
                +## Worker utilization
                @@ -53,3 +55,9 @@
                -there is more work to do than the process can get through. On the other hand, if
                -you have processes that sit around doing nothing, then they're just eating up
                -resources.
                +there is more work to do than the process can get through, and requests will end up with additional latency. On the other hand, if
                +you have processes that sit around doing nothing, then you're wasting resources and money.
                +
                +In general, you are making a tradeoff between:
                +
                +1. CPU and memory utilization.
                +2. Time spent queueing for a Puma worker to `accept` requests and additional latency caused by CPU contention.
                +
                +If latency is important to you, you will have to accept lower utilization, and vice versa.
                @@ -57,2 +65 @@
                -Watch your CPU utilization over time and aim for about 70% on average. 70%
                -utilization means you've got capacity still but aren't starving threads.
                +## Container/VPS sizing
                @@ -60 +67,16 @@
                -**Measuring utilization**
                +You will have to make a decision about how "big" to make each pod/VPS/server/dyno.
                +
                +**TL:DR;**: 80% of Puma apps will end up deploying "pods" of 4 workers, 5 threads each, 4 vCPU and 8GB of RAM.
                +
                +For the rest of this discussion, we'll adopt the Kubernetes term of "pods".
                +
                +Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make:
                +
                +* **Increasing worker counts decreases latency, but means you scale in bigger "chunks"**. Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                +* **Increasing thread counts will increase throughput, but also latency and memory use** Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50% of wall clock time) will lead to additional request latency and additional memory usage.
                +* **Increasing worker counts decreases memory per worker on average**. More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                +* **Low worker counts (<4) have exceptionally poor throughput**. Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing (see discussion above), which means you will have to run more pods and resources.
                +* **CPU-core-to-worker ratios should be around 1**. If running Puma with `threads > 1`, allocate 1 CPU core (see definition above!) per worker. If single threaded, allocate ~0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core. Using `workers :auto` will size workers to this guidance on most platforms.
                +* **Don't set memory limits unless necessary**. Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +
                +**Measuring utilization and queue time**
                @@ -78 +100 @@
                -      can can also be added as headers.
                +      can also be added as headers.
                @@ -102,0 +125,13 @@
                +
                +## Migrating from Unicorn
                +
                +* If you're migrating from unicorn though, here are some settings to start with:
                +  * Set workers to half the number of unicorn workers you're using
                +  * Set threads to 2
                +  * Enjoy 50% memory savings
                +* As you grow more confident in the thread-safety of your app, you can tune the
                +  workers down and the threads up.
                +
                +## Ubuntu / Systemd (Systemctl) Installation
                +
                +See [systemd.md](systemd.md)
        docs/jungle/README.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/jungle/README.md	2026-01-22 03:33:12.101556481 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/jungle/README.md	2026-01-22 03:33:12.113556375 +0000
                @@ -5 +5 @@
                -See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
                +See [/docs/systemd](https://github.com/puma/puma/blob/main/docs/systemd.md).
        docs/kubernetes.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/kubernetes.md	2026-01-22 03:33:12.101556481 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/kubernetes.md	2026-01-22 03:33:12.113556375 +0000
                @@ -5 +5 @@
                -In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some request might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                +In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some requests might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                @@ -64 +64 @@
                -There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives this request handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                +There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives and handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                @@ -72,8 +72 @@
                -With containerization, you will have to make a decision about how "big" to make each pod. Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make.
                -
                -* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                -* Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50%) will lead to additional request queueing time (latency!) and additional memory usage.
                -* More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                -* Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing, which means you will have to run more pods.
                -* If multithreaded, allocate 1 CPU per worker. If single threaded, allocate 0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core.
                -* Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +See our [deployment docs](./deployment.md) for more information about how to correctly size your pods and choose the right number of workers and threads.
        docs/plugins.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/plugins.md	2026-01-22 03:33:12.101556481 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/plugins.md	2026-01-22 03:33:12.114556366 +0000
                @@ -8 +8 @@
                -* [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb):
                +* [tmp\_restart](https://github.com/puma/puma/blob/main/lib/puma/plugin/tmp_restart.rb):
                @@ -14 +14 @@
                -Plugins are activated in a Puma configuration file (such as `config/puma.rb'`)
                +Plugins are activated in a Puma configuration file (such as `config/puma.rb`)
        docs/signals.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/signals.md	2026-01-22 03:33:12.102556472 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/signals.md	2026-01-22 03:33:12.114556366 +0000
                @@ -36,10 +36,10 @@
                -- `TTIN` increment the worker count by 1
                -- `TTOU` decrement the worker count by 1
                -- `TERM` send `TERM` to worker. The worker will attempt to finish then exit.
                -- `USR2` restart workers. This also reloads the Puma configuration file, if there is one.
                -- `USR1` restart workers in phases, a rolling restart. This will not reload the configuration file.
                -- `HUP ` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided, it will behave like `INT`
                -- `INT ` equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                -- `CHLD`
                -- `URG ` refork workers in phases from worker 0 if `fork_workers` option is enabled.
                -- `INFO` print backtraces of all puma threads
                +- `TTIN`: Increment the worker count by 1.
                +- `TTOU`: Decrement the worker count by 1.
                +- `TERM`: Send `TERM` to worker. The worker will attempt to finish then exit.
                +- `USR2`: Restart workers. This also reloads the Puma configuration file, if there is one.
                +- `USR1`: Restart workers in phases, a rolling restart. This will not reload the configuration file.
                +- `HUP`:  Reopen log files defined in `stdout_redirect` configuration parameter. If there is no `stdout_redirect` option provided, it will behave like `INT`.
                +- `INT`:  Equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                +- `CHLD`: Reap zombie child processes and wake event loop in `fork_worker` mode.
                +- `URG`:  Refork workers in phases from worker 0 if `fork_worker` option is enabled.
                +- `INFO`: Print backtraces of all Puma threads.
        docs/stats.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/stats.md	2026-01-22 03:33:12.102556472 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/stats.md	2026-01-22 03:33:12.114556366 +0000
                @@ -73 +73 @@
                -* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/master/docs/restart.md)
                +* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/main/docs/restart.md)
        docs/systemd.md
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/docs/systemd.md	2026-01-22 03:33:12.103556463 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/docs/systemd.md	2026-01-22 03:33:12.114556366 +0000
                @@ -122,2 +122,2 @@
                -folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the release folder
                -path (`/srv/projet/releases/1234/tmp/puma.sock`).
                +folder path (ex. `/srv/project/shared/tmp/puma.sock`), not the release folder
                +path (`/srv/project/releases/1234/tmp/puma.sock`).
                @@ -142 +142 @@
                -binds that's not socket activated.
                +binds that are not socket activated.
        ext/puma_http11/puma_http11.c
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:12.105556445 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:12.116556349 +0000
                @@ -11 +10,0 @@
                -#include "ext_help.h"
                @@ -17,13 +16 @@
                -#ifndef MANAGED_STRINGS
                -
                -#ifndef RSTRING_PTR
                -#define RSTRING_PTR(s) (RSTRING(s)->ptr)
                -#endif
                -#ifndef RSTRING_LEN
                -#define RSTRING_LEN(s) (RSTRING(s)->len)
                -#endif
                -
                -#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
                -#define rb_free_chars(e) /* nothing */
                -
                -#endif
                +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
                @@ -54,2 +41,2 @@
                -    rb_global_variable(var);
                -    *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                +  rb_global_variable(var);
                +  *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                @@ -80,2 +67,2 @@
                -	const size_t len;
                -	const char *name;
                +  const size_t len;
                +  const char *name;
                @@ -83 +70 @@
                -	VALUE value;
                +  VALUE value;
                @@ -94,36 +81,36 @@
                -	f("ACCEPT"),
                -	f("ACCEPT_CHARSET"),
                -	f("ACCEPT_ENCODING"),
                -	f("ACCEPT_LANGUAGE"),
                -	f("ALLOW"),
                -	f("AUTHORIZATION"),
                -	f("CACHE_CONTROL"),
                -	f("CONNECTION"),
                -	f("CONTENT_ENCODING"),
                -	fr("CONTENT_LENGTH"),
                -	fr("CONTENT_TYPE"),
                -	f("COOKIE"),
                -	f("DATE"),
                -	f("EXPECT"),
                -	f("FROM"),
                -	f("HOST"),
                -	f("IF_MATCH"),
                -	f("IF_MODIFIED_SINCE"),
                -	f("IF_NONE_MATCH"),
                -	f("IF_RANGE"),
                -	f("IF_UNMODIFIED_SINCE"),
                -	f("KEEP_ALIVE"), /* Firefox sends this */
                -	f("MAX_FORWARDS"),
                -	f("PRAGMA"),
                -	f("PROXY_AUTHORIZATION"),
                -	f("RANGE"),
                -	f("REFERER"),
                -	f("TE"),
                -	f("TRAILER"),
                -	f("TRANSFER_ENCODING"),
                -	f("UPGRADE"),
                -	f("USER_AGENT"),
                -	f("VIA"),
                -	f("X_FORWARDED_FOR"), /* common for proxies */
                -	f("X_REAL_IP"), /* common for proxies */
                -	f("WARNING")
                +  f("ACCEPT"),
                +  f("ACCEPT_CHARSET"),
                +  f("ACCEPT_ENCODING"),
                +  f("ACCEPT_LANGUAGE"),
                +  f("ALLOW"),
                +  f("AUTHORIZATION"),
                +  f("CACHE_CONTROL"),
                +  f("CONNECTION"),
                +  f("CONTENT_ENCODING"),
                +  fr("CONTENT_LENGTH"),
                +  fr("CONTENT_TYPE"),
                +  f("COOKIE"),
                +  f("DATE"),
                +  f("EXPECT"),
                +  f("FROM"),
                +  f("HOST"),
                +  f("IF_MATCH"),
                +  f("IF_MODIFIED_SINCE"),
                +  f("IF_NONE_MATCH"),
                +  f("IF_RANGE"),
                +  f("IF_UNMODIFIED_SINCE"),
                +  f("KEEP_ALIVE"), /* Firefox sends this */
                +  f("MAX_FORWARDS"),
                +  f("PRAGMA"),
                +  f("PROXY_AUTHORIZATION"),
                +  f("RANGE"),
                +  f("REFERER"),
                +  f("TE"),
                +  f("TRAILER"),
                +  f("TRANSFER_ENCODING"),
                +  f("UPGRADE"),
                +  f("USER_AGENT"),
                +  f("VIA"),
                +  f("X_FORWARDED_FOR"), /* common for proxies */
                +  f("X_REAL_IP"), /* common for proxies */
                +  f("WARNING")
                @@ -143 +130 @@
                -      cf->value = rb_str_new(cf->name, cf->len);
                +      cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
                @@ -146 +133 @@
                -      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
                +      cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
                @@ -166 +153 @@
                -void http_field(puma_parser* hp, const char *field, size_t flen,
                +static void http_field(puma_parser* hp, const char *field, size_t flen,
                @@ -189 +176 @@
                -    f = rb_str_new(hp->buf, new_size);
                +    f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
                @@ -211 +198 @@
                -void request_method(puma_parser* hp, const char *at, size_t length)
                +static void request_method(puma_parser* hp, const char *at, size_t length)
                @@ -219 +206 @@
                -void request_uri(puma_parser* hp, const char *at, size_t length)
                +static void request_uri(puma_parser* hp, const char *at, size_t length)
                @@ -229 +216 @@
                -void fragment(puma_parser* hp, const char *at, size_t length)
                +static void fragment(puma_parser* hp, const char *at, size_t length)
                @@ -239 +226 @@
                -void request_path(puma_parser* hp, const char *at, size_t length)
                +static void request_path(puma_parser* hp, const char *at, size_t length)
                @@ -249 +236 @@
                -void query_string(puma_parser* hp, const char *at, size_t length)
                +static void query_string(puma_parser* hp, const char *at, size_t length)
                @@ -259 +246 @@
                -void server_protocol(puma_parser* hp, const char *at, size_t length)
                +static void server_protocol(puma_parser* hp, const char *at, size_t length)
                @@ -268 +255 @@
                -void header_done(puma_parser* hp, const char *at, size_t length)
                +static void header_done(puma_parser* hp, const char *at, size_t length)
                @@ -274,2 +261,5 @@
                -void HttpParser_free(void *data) {
                -  TRACE();
                +static void HttpParser_mark(void *ptr) {
                +  puma_parser *hp = ptr;
                +  rb_gc_mark_movable(hp->request);
                +  rb_gc_mark_movable(hp->body);
                +}
                @@ -277,3 +267,2 @@
                -  if(data) {
                -    xfree(data);
                -  }
                +static size_t HttpParser_size(const void *ptr) {
                +  return sizeof(puma_parser);
                @@ -282 +271 @@
                -void HttpParser_mark(void *ptr) {
                +static void HttpParser_compact(void *ptr) {
                @@ -284,2 +273,2 @@
                -  if(hp->request) rb_gc_mark(hp->request);
                -  if(hp->body) rb_gc_mark(hp->body);
                +  hp->request = rb_gc_location(hp->request);
                +  hp->body = rb_gc_location(hp->body);
                @@ -288,4 +277,9 @@
                -const rb_data_type_t HttpParser_data_type = {
                -    "HttpParser",
                -    { HttpParser_mark, HttpParser_free, 0 },
                -    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
                +static const rb_data_type_t HttpParser_data_type = {
                +    .wrap_struct_name = "Puma::HttpParser",
                +    .function = {
                +      .dmark = HttpParser_mark,
                +      .dfree = RUBY_TYPED_DEFAULT_FREE,
                +      .dsize = HttpParser_size,
                +      .dcompact = HttpParser_compact,
                +    },
                +    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
                @@ -294 +288 @@
                -VALUE HttpParser_alloc(VALUE klass)
                +static VALUE HttpParser_alloc(VALUE klass)
                @@ -297 +290,0 @@
                -  TRACE();
                @@ -312,0 +306,10 @@
                +static inline puma_parser *HttpParser_unwrap(VALUE self)
                +{
                +  puma_parser *http;
                +  TypedData_Get_Struct(self, puma_parser, &HttpParser_data_type, http);
                +  if (http == NULL) {
                +    rb_raise(rb_eArgError, "%s", "NULL http_parser found");
                +  }
                +  return http;
                +}
                +
                @@ -319 +322 @@
                -VALUE HttpParser_init(VALUE self)
                +static VALUE HttpParser_init(VALUE self)
                @@ -321,2 +324 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -336 +338 @@
                -VALUE HttpParser_reset(VALUE self)
                +static VALUE HttpParser_reset(VALUE self)
                @@ -338,2 +340 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -353 +354 @@
                -VALUE HttpParser_finish(VALUE self)
                +static VALUE HttpParser_finish(VALUE self)
                @@ -355,2 +356 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -380 +380 @@
                -VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                +static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                @@ -382 +382 @@
                -  puma_parser *http = NULL;
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -387,2 +386,0 @@
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                -
                @@ -390 +388 @@
                -  dptr = rb_extract_chars(data, &dlen);
                +  RSTRING_GETMEM(data, dptr, dlen);
                @@ -393 +390,0 @@
                -    rb_free_chars(dptr);
                @@ -399 +395,0 @@
                -    rb_free_chars(dptr);
                @@ -418 +414 @@
                -VALUE HttpParser_has_error(VALUE self)
                +static VALUE HttpParser_has_error(VALUE self)
                @@ -420,2 +416 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -433 +428 @@
                -VALUE HttpParser_is_finished(VALUE self)
                +static VALUE HttpParser_is_finished(VALUE self)
                @@ -435,2 +430 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -449 +443 @@
                -VALUE HttpParser_nread(VALUE self)
                +static VALUE HttpParser_nread(VALUE self)
                @@ -451,2 +445 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -463,3 +456,2 @@
                -VALUE HttpParser_body(VALUE self) {
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +static VALUE HttpParser_body(VALUE self) {
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -474 +466 @@
                -void Init_puma_http11(void)
                +RUBY_FUNC_EXPORTED void Init_puma_http11(void)
        lib/puma/app/status.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/app/status.rb	2026-01-22 03:33:12.105556445 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/app/status.rb	2026-01-22 03:33:12.117556340 +0000
                @@ -9,0 +10 @@
                +      READ_ONLY_COMMANDS = %w[gc-stats stats].freeze
                @@ -12,0 +14 @@
                +      # @param data_only [Boolean] if true, restrict to read-only data commands
                @@ -14 +16 @@
                -      def initialize(launcher, token = nil)
                +      def initialize(launcher, token: nil, data_only: false)
                @@ -16,0 +19 @@
                +        @enabled_commands = READ_ONLY_COMMANDS if data_only
                @@ -27,0 +31,5 @@
                +        command = env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +        if @enabled_commands && !@enabled_commands.include?(command)
                +          return rack_response(404, "Command #{command.inspect} unavailable", 'text/plain')
                +        end
                +
                @@ -29 +37 @@
                -          case env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +          case command
        lib/puma/cluster.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/cluster.rb	2026-01-22 03:33:12.106556437 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/cluster.rb	2026-01-22 03:33:12.117556340 +0000
                @@ -189 +189 @@
                -        w = @workers.find { |x| x.phase != @phase }
                +        w = @workers.find { |x| x.phase < @phase }
                @@ -224 +223,0 @@
                -      server = start_server if preload?
                @@ -229 +228 @@
                -                              server: server
                +                              app: (app if preload?)
        lib/puma/cluster/worker.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:12.106556437 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:12.117556340 +0000
                @@ -17 +17 @@
                -      def initialize(index:, master:, launcher:, pipes:, server: nil)
                +      def initialize(index:, master:, launcher:, pipes:, app: nil)
                @@ -26 +26,2 @@
                -        @server = server
                +        @app = app
                +        @server = nil
                @@ -60 +61 @@
                -        server = @server ||= start_server
                +          @server = start_server
                @@ -88 +89 @@
                -                  server.begin_restart(true)
                +                  @server.begin_restart(true)
                @@ -106 +107 @@
                -          server.stop
                +          @server.stop
                @@ -118 +119 @@
                -          server_thread = server.run
                +          server_thread = @server.run
                @@ -132 +133 @@
                -                hsh = server.stats
                +                hsh = @server.stats
                @@ -138 +139 @@
                -                server.reset_max
                +                @server.reset_max
                @@ -167 +168 @@
                -                                  server: @server
                +                                  app: @app
        lib/puma/configuration.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/configuration.rb	2026-01-22 03:33:12.106556437 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/configuration.rb	2026-01-22 03:33:12.118556331 +0000
                @@ -200 +200 @@
                -    attr_reader :plugins, :events, :hooks
                +    attr_reader :plugins, :events, :hooks, :_options
                @@ -241,6 +241,2 @@
                -      workers = if env['WEB_CONCURRENCY'] == 'auto'
                -        require_processor_counter
                -        ::Concurrent.available_processor_count
                -      else
                -        env['WEB_CONCURRENCY']
                -      end
                +      workers_env = env['WEB_CONCURRENCY']
                +      workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
                @@ -252 +248 @@
                -        workers: workers && workers != "" && Integer(workers),
                +        workers: workers,
                @@ -383 +379 @@
                -        WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
                +        WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
                @@ -386,0 +383,11 @@
                +    end
                +
                +    def parse_workers(value)
                +      if value == :auto || value == 'auto'
                +        require_processor_counter
                +        Integer(::Concurrent.available_processor_count)
                +      else
                +        Integer(value)
                +      end
                +    rescue ArgumentError, TypeError
                +      raise ArgumentError, "workers must be an Integer or :auto"
        lib/puma/const.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/const.rb	2026-01-22 03:33:12.106556437 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/const.rb	2026-01-22 03:33:12.118556331 +0000
                @@ -103,2 +103,2 @@
                -    PUMA_VERSION = VERSION = "7.1.0"
                -    CODE_NAME = "Neon Witch"
                +    PUMA_VERSION = VERSION = "7.2.0"
                +    CODE_NAME = "On The Corner"
        lib/puma/dsl.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/dsl.rb	2026-01-22 03:33:12.107556428 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/dsl.rb	2026-01-22 03:33:12.118556331 +0000
                @@ -218,0 +219,2 @@
                +    # @example
                +    #   activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
                @@ -242,0 +245 @@
                +      @options[:control_data_only] = opts[:data_only] if opts[:data_only]
                @@ -669,2 +672,2 @@
                -    # How many worker processes to run.  Typically this is set to
                -    # the number of available cores.
                +    # How many worker processes to run. Typically this is set to the number of
                +    # available cores.
                @@ -673 +676,6 @@
                -    # set, otherwise 0.
                +    # set, otherwise 0. Passing +:auto+ will set the value to
                +    # +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
                +    # On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
                +    # will round down. If it rounds down to 0, Puma will run in single mode and
                +    # cluster-only hooks like +before_worker_boot+ will not execute.
                +    # If you rely on cluster-only hooks, set an explicit worker count.
                @@ -675 +683 @@
                -    # @note Cluster mode only.
                +    # A value of 0 or nil means run in single mode.
                @@ -678,0 +687 @@
                +    #   workers :auto
                @@ -683 +692 @@
                -      @options[:workers] = count.to_i
                +      @options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
                @@ -997,0 +1007 @@
                +    # @note When using `fork_worker`, this only applies to worker 0.
                @@ -1381 +1391 @@
                -    # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
                +    # @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
        lib/puma/launcher.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/launcher.rb	2026-01-22 03:33:12.107556428 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/launcher.rb	2026-01-22 03:33:12.119556322 +0000
                @@ -45 +45 @@
                -      ## Minimal initialization for a potential early restart (e.g. when pruning bundle)
                +      ## Minimal initialization before potential early restart (e.g. from bundle pruning)
                @@ -47,0 +48,2 @@
                +      # Advertise the CLI Configuration before config files are loaded
                +      Puma.cli_config = @config if defined?(Puma.cli_config)
                @@ -73,2 +75 @@
                -      # Advertise the Configuration
                -      Puma.cli_config = @config if defined?(Puma.cli_config)
                +      # Log after prune_bundler! to avoid duplicate logging if a restart occurs
        lib/puma/reactor.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/reactor.rb	2026-01-22 03:33:12.109556410 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/reactor.rb	2026-01-22 03:33:12.120556313 +0000
                @@ -78 +77,0 @@
                -      close_selector = true
                @@ -84 +82,0 @@
                -          monitor_wake_up = false
                @@ -86 +83,0 @@
                -            monitor_wake_up = true
                @@ -106,8 +103 @@
                -        # NoMethodError may be rarely raised when calling @selector.select, which
                -        # is odd.  Regardless, it may continue for thousands of calls if retried.
                -        # Also, when it raises, @selector.close also raises an error.
                -        if !monitor_wake_up && NoMethodError === e
                -          close_selector = false
                -        else
                -          retry
                -        end
                +        retry
                @@ -114,0 +105 @@
                +
                @@ -117 +108 @@
                -      @selector.close if close_selector
                +      @selector.close
        lib/puma/request.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/request.rb	2026-01-22 03:33:12.109556410 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/request.rb	2026-01-22 03:33:12.121556305 +0000
                @@ -39 +39 @@
                -    # It'll return +false+ when the connection is closed, this doesn't mean
                +    # It'll return +:close+ when the connection is closed, this doesn't mean
                @@ -41,0 +42,3 @@
                +    # It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
                +    # Which may contain additional requests.
                +    #
                @@ -48,2 +51 @@
                -    # @return [Boolean,:async]
                -    #
                +    # @return [:close, :keep_alive, :async]
                @@ -57 +59 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -170 +172 @@
                -    # @return [Boolean,:async] keep-alive status or `:async`
                +    # @return [:close, :keep_alive, :async]
                @@ -176 +178 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -247 +249 @@
                -          return keep_alive
                +          return keep_alive ? :keep_alive : :close
                @@ -273 +275 @@
                -      !shutting_down? && keep_alive
                +      !shutting_down? && keep_alive ? :keep_alive : :close
        lib/puma/runner.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/runner.rb	2026-01-22 03:33:12.109556410 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/runner.rb	2026-01-22 03:33:12.121556305 +0000
                @@ -73 +73 @@
                -      app = Puma::App::Status.new @launcher, token
                +      app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
        lib/puma/server.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/server.rb	2026-01-22 03:33:12.109556410 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/server.rb	2026-01-22 03:33:12.121556305 +0000
                @@ -302 +302 @@
                -    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).
                +    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
                @@ -504 +504 @@
                -          when false
                +          when :close
                @@ -507 +507 @@
                -          when true
                +          when :keep_alive
        lib/puma/single.rb
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/lib/puma/single.rb	2026-01-22 03:33:12.109556410 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/lib/puma/single.rb	2026-01-22 03:33:12.121556305 +0000
                @@ -52,2 +52,2 @@
                -      @server = server = start_server
                -      server_thread = server.run
                +      @server = start_server
                +      server_thread = @server.run
        tools/Dockerfile
                --- /tmp/d20260122-755-pz1kh6/puma-7.1.0/tools/Dockerfile	2026-01-22 03:33:12.110556401 +0000
                +++ /tmp/d20260122-755-pz1kh6/puma-7.2.0/tools/Dockerfile	2026-01-22 03:33:12.122556296 +0000
                @@ -1,0 +2,2 @@
                +# Build (MRI): docker build -f tools/Dockerfile .
                +# Build (JRuby): docker build -f tools/Dockerfile --build-arg RUBY_IMAGE=jruby:9.4 .
                @@ -3 +5,2 @@
                -FROM ruby:3.2
                +ARG RUBY_IMAGE=ruby:latest
                +FROM ${RUBY_IMAGE}
                @@ -5 +8,2 @@
                -RUN apt-get update && apt-get install -y ragel
                +# Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
                +ARG BUNDLE_FROZEN=true
                @@ -7,2 +11,6 @@
                -# throw errors if Gemfile has been modified since Gemfile.lock
                -RUN bundle config --global frozen 1
                +RUN apt-get update \
                +  && apt-get install -y --no-install-recommends ragel procps git \
                +  && rm -rf /var/lib/apt/lists/*
                +
                +# Only freeze Bundler and compile native extensions when using MRI.
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ] && [ "${BUNDLE_FROZEN}" = "true" ]; then bundle config --global frozen 1; fi
                @@ -15 +23 @@
                -RUN bundle exec rake compile
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi

@github-actions
Copy link
Contributor

gem compare --diff puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
        History.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/History.md	2026-01-22 03:33:13.614412672 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/History.md	2026-01-22 03:33:13.627412652 +0000
                @@ -0,0 +1,35 @@
                +## 7.2.0 / 2026-01-20
                +
                +* Features
                +  * Add workers `:auto` ([#3827])
                +  * Make it possible to restrict control server commands to stats ([#3787])
                +
                +* Bugfixes
                +  * Don't break if `WEB_CONCURRENCY` is set to a blank string ([#3837])
                +  * Don't share server between worker 0 and descendants on refork ([#3602])
                +  * Fix phase check race condition in `Puma::Cluster#check_workers` ([#3690])
                +  * Fix advertising of CLI config before config files are loaded ([#3823])
                +
                +* Performance
                +  * 17% faster HTTP parsing through pre-interning env keys ([#3825])
                +  * Implement `dsize` and `dcompact` functions for `Puma::HttpParser`, which makes Puma's C-extension GC-compactible ([#3828])
                +
                +* Refactor
                +  * Remove `NoMethodError` rescue in `Reactor#select_loop` ([#3831])
                +  * Various cleanups in the C extension ([#3814])
                +  * Monomorphize `handle_request` return ([#3802])
                +
                +* Docs
                +  * Change link to `docs/deployment.md` in `README.md` ([#3848])
                +  * Fix formatting for each signal description in signals.md ([#3813])
                +  * Update deployment and Kubernetes docs with Puma configuration tips ([#3807])
                +  * Rename master to main ([#3809], [#3808], [#3800])
                +  * Fix some minor typos in the docs ([#3804])
                +  * Add `GOVERNANCE.md`, `MAINTAINERS` ([#3826])
                +  * Remove Code Climate badge ([#3820])
                +  * Add @joshuay03 to the maintainer list
                +
                +* CI
                +  * Use Minitest 6 where applicable ([#3859])
                +  * Many test suite improvements and flake fixes ([#3861], [#3863], [#3860], [#3852], [#3857], [#3856], [#3845], [#3843], [#3842], [#3841], [#3822], [#3817], [#3764])
                +
                @@ -2260,0 +2296,36 @@
                +
                +[#3863]:https://github.com/puma/puma/pull/3863     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3861]:https://github.com/puma/puma/pull/3861     "PR by MSP-Greg, merged 2026-01-20"
                +[#3860]:https://github.com/puma/puma/pull/3860     "PR by MSP-Greg, merged 2026-01-16"
                +[#3859]:https://github.com/puma/puma/pull/3859     "PR by MSP-Greg, merged 2026-01-16"
                +[#3857]:https://github.com/puma/puma/pull/3857     "PR by Aaron Patterson, merged 2026-01-12"
                +[#3856]:https://github.com/puma/puma/pull/3856     "PR by MSP-Greg, merged 2026-01-12"
                +[#3852]:https://github.com/puma/puma/pull/3852     "PR by Miłosz Bieniek, merged 2026-01-14"
                +[#3848]:https://github.com/puma/puma/pull/3848     "PR by Miłosz Bieniek, merged 2025-12-27"
                +[#3845]:https://github.com/puma/puma/pull/3845     "PR by MSP-Greg, merged 2025-12-19"
                +[#3843]:https://github.com/puma/puma/pull/3843     "PR by MSP-Greg, merged 2025-12-18"
                +[#3842]:https://github.com/puma/puma/pull/3842     "PR by MSP-Greg, merged 2025-12-18"
                +[#3841]:https://github.com/puma/puma/pull/3841     "PR by MSP-Greg, merged 2025-12-18"
                +[#3837]:https://github.com/puma/puma/pull/3837     "PR by John Bachir, merged 2026-01-09"
                +[#3833]:https://github.com/puma/puma/pull/3833     "PR by Patrik Ragnarsson, merged 2025-11-25"
                +[#3831]:https://github.com/puma/puma/pull/3831     "PR by Joshua Young, merged 2025-11-25"
                +[#3828]:https://github.com/puma/puma/pull/3828     "PR by Jean Boussier, merged 2025-11-21"
                +[#3827]:https://github.com/puma/puma/pull/3827     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3826]:https://github.com/puma/puma/pull/3826     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3825]:https://github.com/puma/puma/pull/3825     "PR by Jean Boussier, merged 2025-11-19"
                +[#3823]:https://github.com/puma/puma/pull/3823     "PR by Joshua Young, merged 2025-11-18"
                +[#3822]:https://github.com/puma/puma/pull/3822     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3820]:https://github.com/puma/puma/pull/3820     "PR by Nate Berkopec, merged 2025-11-19"
                +[#3817]:https://github.com/puma/puma/pull/3817     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3814]:https://github.com/puma/puma/pull/3814     "PR by Jean Boussier, merged 2025-11-17"
                +[#3813]:https://github.com/puma/puma/pull/3813     "PR by Masafumi Koba, merged 2025-11-17"
                +[#3809]:https://github.com/puma/puma/pull/3809     "PR by Patrik Ragnarsson, merged 2025-10-26"
                +[#3808]:https://github.com/puma/puma/pull/3808     "PR by Nymuxyzo, merged 2025-10-26"
                +[#3807]:https://github.com/puma/puma/pull/3807     "PR by Nate Berkopec, merged 2025-10-28"
                +[#3804]:https://github.com/puma/puma/pull/3804     "PR by Joe Rafaniello, merged 2025-10-21"
                +[#3802]:https://github.com/puma/puma/pull/3802     "PR by Richard Schneeman, merged 2025-10-20"
                +[#3800]:https://github.com/puma/puma/pull/3800     "PR by MSP-Greg, merged 2025-10-19"
                +[#3787]:https://github.com/puma/puma/pull/3787     "PR by Stan Hu, merged 2025-10-17"
                +[#3764]:https://github.com/puma/puma/pull/3764     "PR by MSP-Greg, merged 2025-10-17"
                +[#3690]:https://github.com/puma/puma/pull/3690     "PR by Joshua Young, merged 2025-11-18"
                +[#3602]:https://github.com/puma/puma/pull/3602     "PR by Joshua Young, merged 2025-11-28"
        README.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/README.md	2026-01-22 03:33:13.614412672 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/README.md	2026-01-22 03:33:13.627412652 +0000
                @@ -7,2 +7 @@
                -[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amaster)
                -[![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
                +[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amain)
                @@ -85 +84 @@
                -Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb).
                +Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb).
                @@ -88 +87 @@
                -[test](https://github.com/puma/puma/tree/master/test/config) suite.
                +[test](https://github.com/puma/puma/tree/main/test/config) suite.
                @@ -118,0 +118,9 @@
                +When using a config file, most applications can simply set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of worker processes to the available processors:
                +
                +```ruby
                +# config/puma.rb
                +workers :auto
                +```
                +
                +See [`workers :auto` gotchas](lib/puma/dsl.rb).
                +
                @@ -121 +129 @@
                -If the `WEB_CONCURRENCY` environment variable is set to `"auto"` and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#available_processor_count-class_method).
                +If `workers` is set to `:auto`, or the `WEB_CONCURRENCY` environment variable is set to `"auto"`, and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://msp-greg.github.io/concurrent-ruby/Concurrent.html#available_processor_count-class_method).
                @@ -123 +131 @@
                -For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](https://github.com/puma/puma/blob/9282a8efa5a0c48e39c60d22ca70051a25df9f55/docs/kubernetes.md#workers-per-pod-and-other-config-issues).
                +For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](docs/deployment.md).
                @@ -229 +237 @@
                -textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
                +textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/main/lib/puma/server.rb)).
                @@ -388 +396 @@
                -Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the status app has available.
                +Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/main/lib/puma/app/status.rb) to see what the status app has available.
                @@ -420 +428 @@
                -Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to see all available options.
                +Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb) to see all available options.
        docs/deployment.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/deployment.md	2026-01-22 03:33:13.615412671 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/deployment.md	2026-01-22 03:33:13.628412650 +0000
                @@ -18,0 +19,7 @@
                +In general, use single mode only if:
                +
                +* You are using JRuby, TruffleRuby or another fully-multithreaded implementation of Ruby
                +* You are using MRI but in an environment where only 1 CPU core is available.
                +
                +Otherwise, you'll want to use cluster mode to utilize all available CPU resources.
                +
                @@ -22 +29 @@
                -Here are some tips for cluster mode:
                +## Cluster Mode Tips
                @@ -24 +31 @@
                -### MRI
                +For the purposes of Puma provisioning, "CPU cores" means:
                @@ -26,4 +33,2 @@
                -* Use cluster mode and set the number of workers to 1.5x the number of CPU cores
                -  in the machine, starting from a minimum of 2.
                -* Set the number of threads to desired concurrent requests/number of workers.
                -  Puma defaults to 5, and that's a decent number.
                +1. On ARM, the number of physical cores.
                +2. On x86, the number of logical cores, hyperthreads, or vCPUs (these words all mean the same thing).
                @@ -31 +36 @@
                -#### Migrating from Unicorn
                +Set your config with the following process:
                @@ -33,6 +38,3 @@
                -* If you're migrating from unicorn though, here are some settings to start with:
                -  * Set workers to half the number of unicorn workers you're using
                -  * Set threads to 2
                -  * Enjoy 50% memory savings
                -* As you grow more confident in the thread-safety of your app, you can tune the
                -  workers down and the threads up.
                +* Use cluster mode and set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of CPU cores on the machine (minimum 2, otherwise use single mode!). If you can't add the gem, set the worker count manually to the available CPU cores.
                +* Set the number of threads to desired concurrent requests/number of workers.
                +  Puma defaults to 5, and that's a decent number.
                @@ -40 +42 @@
                -#### Ubuntu / Systemd (Systemctl) Installation
                +For most deployments, adding `concurrent-ruby` and using `workers :auto` is the right starting point.
                @@ -42 +44 @@
                -See [systemd.md](systemd.md)
                +See [`workers :auto` gotchas](../lib/puma/dsl.rb).
                @@ -44 +46 @@
                -#### Worker utilization
                +## Worker utilization
                @@ -53,3 +55,9 @@
                -there is more work to do than the process can get through. On the other hand, if
                -you have processes that sit around doing nothing, then they're just eating up
                -resources.
                +there is more work to do than the process can get through, and requests will end up with additional latency. On the other hand, if
                +you have processes that sit around doing nothing, then you're wasting resources and money.
                +
                +In general, you are making a tradeoff between:
                +
                +1. CPU and memory utilization.
                +2. Time spent queueing for a Puma worker to `accept` requests and additional latency caused by CPU contention.
                +
                +If latency is important to you, you will have to accept lower utilization, and vice versa.
                @@ -57,2 +65 @@
                -Watch your CPU utilization over time and aim for about 70% on average. 70%
                -utilization means you've got capacity still but aren't starving threads.
                +## Container/VPS sizing
                @@ -60 +67,16 @@
                -**Measuring utilization**
                +You will have to make a decision about how "big" to make each pod/VPS/server/dyno.
                +
                +**TL:DR;**: 80% of Puma apps will end up deploying "pods" of 4 workers, 5 threads each, 4 vCPU and 8GB of RAM.
                +
                +For the rest of this discussion, we'll adopt the Kubernetes term of "pods".
                +
                +Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make:
                +
                +* **Increasing worker counts decreases latency, but means you scale in bigger "chunks"**. Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                +* **Increasing thread counts will increase throughput, but also latency and memory use** Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50% of wall clock time) will lead to additional request latency and additional memory usage.
                +* **Increasing worker counts decreases memory per worker on average**. More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                +* **Low worker counts (<4) have exceptionally poor throughput**. Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing (see discussion above), which means you will have to run more pods and resources.
                +* **CPU-core-to-worker ratios should be around 1**. If running Puma with `threads > 1`, allocate 1 CPU core (see definition above!) per worker. If single threaded, allocate ~0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core. Using `workers :auto` will size workers to this guidance on most platforms.
                +* **Don't set memory limits unless necessary**. Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +
                +**Measuring utilization and queue time**
                @@ -78 +100 @@
                -      can can also be added as headers.
                +      can also be added as headers.
                @@ -102,0 +125,13 @@
                +
                +## Migrating from Unicorn
                +
                +* If you're migrating from unicorn though, here are some settings to start with:
                +  * Set workers to half the number of unicorn workers you're using
                +  * Set threads to 2
                +  * Enjoy 50% memory savings
                +* As you grow more confident in the thread-safety of your app, you can tune the
                +  workers down and the threads up.
                +
                +## Ubuntu / Systemd (Systemctl) Installation
                +
                +See [systemd.md](systemd.md)
        docs/jungle/README.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/jungle/README.md	2026-01-22 03:33:13.616412669 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/jungle/README.md	2026-01-22 03:33:13.629412649 +0000
                @@ -5 +5 @@
                -See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
                +See [/docs/systemd](https://github.com/puma/puma/blob/main/docs/systemd.md).
        docs/kubernetes.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/kubernetes.md	2026-01-22 03:33:13.616412669 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/kubernetes.md	2026-01-22 03:33:13.629412649 +0000
                @@ -5 +5 @@
                -In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some request might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                +In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some requests might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                @@ -64 +64 @@
                -There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives this request handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                +There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives and handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                @@ -72,8 +72 @@
                -With containerization, you will have to make a decision about how "big" to make each pod. Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make.
                -
                -* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                -* Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50%) will lead to additional request queueing time (latency!) and additional memory usage.
                -* More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                -* Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing, which means you will have to run more pods.
                -* If multithreaded, allocate 1 CPU per worker. If single threaded, allocate 0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core.
                -* Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +See our [deployment docs](./deployment.md) for more information about how to correctly size your pods and choose the right number of workers and threads.
        docs/plugins.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/plugins.md	2026-01-22 03:33:13.616412669 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/plugins.md	2026-01-22 03:33:13.629412649 +0000
                @@ -8 +8 @@
                -* [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb):
                +* [tmp\_restart](https://github.com/puma/puma/blob/main/lib/puma/plugin/tmp_restart.rb):
                @@ -14 +14 @@
                -Plugins are activated in a Puma configuration file (such as `config/puma.rb'`)
                +Plugins are activated in a Puma configuration file (such as `config/puma.rb`)
        docs/signals.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/signals.md	2026-01-22 03:33:13.617412668 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/signals.md	2026-01-22 03:33:13.630412647 +0000
                @@ -36,10 +36,10 @@
                -- `TTIN` increment the worker count by 1
                -- `TTOU` decrement the worker count by 1
                -- `TERM` send `TERM` to worker. The worker will attempt to finish then exit.
                -- `USR2` restart workers. This also reloads the Puma configuration file, if there is one.
                -- `USR1` restart workers in phases, a rolling restart. This will not reload the configuration file.
                -- `HUP ` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided, it will behave like `INT`
                -- `INT ` equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                -- `CHLD`
                -- `URG ` refork workers in phases from worker 0 if `fork_workers` option is enabled.
                -- `INFO` print backtraces of all puma threads
                +- `TTIN`: Increment the worker count by 1.
                +- `TTOU`: Decrement the worker count by 1.
                +- `TERM`: Send `TERM` to worker. The worker will attempt to finish then exit.
                +- `USR2`: Restart workers. This also reloads the Puma configuration file, if there is one.
                +- `USR1`: Restart workers in phases, a rolling restart. This will not reload the configuration file.
                +- `HUP`:  Reopen log files defined in `stdout_redirect` configuration parameter. If there is no `stdout_redirect` option provided, it will behave like `INT`.
                +- `INT`:  Equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                +- `CHLD`: Reap zombie child processes and wake event loop in `fork_worker` mode.
                +- `URG`:  Refork workers in phases from worker 0 if `fork_worker` option is enabled.
                +- `INFO`: Print backtraces of all Puma threads.
        docs/stats.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/stats.md	2026-01-22 03:33:13.618412666 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/stats.md	2026-01-22 03:33:13.630412647 +0000
                @@ -73 +73 @@
                -* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/master/docs/restart.md)
                +* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/main/docs/restart.md)
        docs/systemd.md
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/docs/systemd.md	2026-01-22 03:33:13.618412666 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/docs/systemd.md	2026-01-22 03:33:13.630412647 +0000
                @@ -122,2 +122,2 @@
                -folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the release folder
                -path (`/srv/projet/releases/1234/tmp/puma.sock`).
                +folder path (ex. `/srv/project/shared/tmp/puma.sock`), not the release folder
                +path (`/srv/project/releases/1234/tmp/puma.sock`).
                @@ -142 +142 @@
                -binds that's not socket activated.
                +binds that are not socket activated.
        ext/puma_http11/puma_http11.c
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:13.620412663 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:13.632412644 +0000
                @@ -11 +10,0 @@
                -#include "ext_help.h"
                @@ -17,13 +16 @@
                -#ifndef MANAGED_STRINGS
                -
                -#ifndef RSTRING_PTR
                -#define RSTRING_PTR(s) (RSTRING(s)->ptr)
                -#endif
                -#ifndef RSTRING_LEN
                -#define RSTRING_LEN(s) (RSTRING(s)->len)
                -#endif
                -
                -#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
                -#define rb_free_chars(e) /* nothing */
                -
                -#endif
                +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
                @@ -54,2 +41,2 @@
                -    rb_global_variable(var);
                -    *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                +  rb_global_variable(var);
                +  *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                @@ -80,2 +67,2 @@
                -	const size_t len;
                -	const char *name;
                +  const size_t len;
                +  const char *name;
                @@ -83 +70 @@
                -	VALUE value;
                +  VALUE value;
                @@ -94,36 +81,36 @@
                -	f("ACCEPT"),
                -	f("ACCEPT_CHARSET"),
                -	f("ACCEPT_ENCODING"),
                -	f("ACCEPT_LANGUAGE"),
                -	f("ALLOW"),
                -	f("AUTHORIZATION"),
                -	f("CACHE_CONTROL"),
                -	f("CONNECTION"),
                -	f("CONTENT_ENCODING"),
                -	fr("CONTENT_LENGTH"),
                -	fr("CONTENT_TYPE"),
                -	f("COOKIE"),
                -	f("DATE"),
                -	f("EXPECT"),
                -	f("FROM"),
                -	f("HOST"),
                -	f("IF_MATCH"),
                -	f("IF_MODIFIED_SINCE"),
                -	f("IF_NONE_MATCH"),
                -	f("IF_RANGE"),
                -	f("IF_UNMODIFIED_SINCE"),
                -	f("KEEP_ALIVE"), /* Firefox sends this */
                -	f("MAX_FORWARDS"),
                -	f("PRAGMA"),
                -	f("PROXY_AUTHORIZATION"),
                -	f("RANGE"),
                -	f("REFERER"),
                -	f("TE"),
                -	f("TRAILER"),
                -	f("TRANSFER_ENCODING"),
                -	f("UPGRADE"),
                -	f("USER_AGENT"),
                -	f("VIA"),
                -	f("X_FORWARDED_FOR"), /* common for proxies */
                -	f("X_REAL_IP"), /* common for proxies */
                -	f("WARNING")
                +  f("ACCEPT"),
                +  f("ACCEPT_CHARSET"),
                +  f("ACCEPT_ENCODING"),
                +  f("ACCEPT_LANGUAGE"),
                +  f("ALLOW"),
                +  f("AUTHORIZATION"),
                +  f("CACHE_CONTROL"),
                +  f("CONNECTION"),
                +  f("CONTENT_ENCODING"),
                +  fr("CONTENT_LENGTH"),
                +  fr("CONTENT_TYPE"),
                +  f("COOKIE"),
                +  f("DATE"),
                +  f("EXPECT"),
                +  f("FROM"),
                +  f("HOST"),
                +  f("IF_MATCH"),
                +  f("IF_MODIFIED_SINCE"),
                +  f("IF_NONE_MATCH"),
                +  f("IF_RANGE"),
                +  f("IF_UNMODIFIED_SINCE"),
                +  f("KEEP_ALIVE"), /* Firefox sends this */
                +  f("MAX_FORWARDS"),
                +  f("PRAGMA"),
                +  f("PROXY_AUTHORIZATION"),
                +  f("RANGE"),
                +  f("REFERER"),
                +  f("TE"),
                +  f("TRAILER"),
                +  f("TRANSFER_ENCODING"),
                +  f("UPGRADE"),
                +  f("USER_AGENT"),
                +  f("VIA"),
                +  f("X_FORWARDED_FOR"), /* common for proxies */
                +  f("X_REAL_IP"), /* common for proxies */
                +  f("WARNING")
                @@ -143 +130 @@
                -      cf->value = rb_str_new(cf->name, cf->len);
                +      cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
                @@ -146 +133 @@
                -      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
                +      cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
                @@ -166 +153 @@
                -void http_field(puma_parser* hp, const char *field, size_t flen,
                +static void http_field(puma_parser* hp, const char *field, size_t flen,
                @@ -189 +176 @@
                -    f = rb_str_new(hp->buf, new_size);
                +    f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
                @@ -211 +198 @@
                -void request_method(puma_parser* hp, const char *at, size_t length)
                +static void request_method(puma_parser* hp, const char *at, size_t length)
                @@ -219 +206 @@
                -void request_uri(puma_parser* hp, const char *at, size_t length)
                +static void request_uri(puma_parser* hp, const char *at, size_t length)
                @@ -229 +216 @@
                -void fragment(puma_parser* hp, const char *at, size_t length)
                +static void fragment(puma_parser* hp, const char *at, size_t length)
                @@ -239 +226 @@
                -void request_path(puma_parser* hp, const char *at, size_t length)
                +static void request_path(puma_parser* hp, const char *at, size_t length)
                @@ -249 +236 @@
                -void query_string(puma_parser* hp, const char *at, size_t length)
                +static void query_string(puma_parser* hp, const char *at, size_t length)
                @@ -259 +246 @@
                -void server_protocol(puma_parser* hp, const char *at, size_t length)
                +static void server_protocol(puma_parser* hp, const char *at, size_t length)
                @@ -268 +255 @@
                -void header_done(puma_parser* hp, const char *at, size_t length)
                +static void header_done(puma_parser* hp, const char *at, size_t length)
                @@ -274,2 +261,5 @@
                -void HttpParser_free(void *data) {
                -  TRACE();
                +static void HttpParser_mark(void *ptr) {
                +  puma_parser *hp = ptr;
                +  rb_gc_mark_movable(hp->request);
                +  rb_gc_mark_movable(hp->body);
                +}
                @@ -277,3 +267,2 @@
                -  if(data) {
                -    xfree(data);
                -  }
                +static size_t HttpParser_size(const void *ptr) {
                +  return sizeof(puma_parser);
                @@ -282 +271 @@
                -void HttpParser_mark(void *ptr) {
                +static void HttpParser_compact(void *ptr) {
                @@ -284,2 +273,2 @@
                -  if(hp->request) rb_gc_mark(hp->request);
                -  if(hp->body) rb_gc_mark(hp->body);
                +  hp->request = rb_gc_location(hp->request);
                +  hp->body = rb_gc_location(hp->body);
                @@ -288,4 +277,9 @@
                -const rb_data_type_t HttpParser_data_type = {
                -    "HttpParser",
                -    { HttpParser_mark, HttpParser_free, 0 },
                -    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
                +static const rb_data_type_t HttpParser_data_type = {
                +    .wrap_struct_name = "Puma::HttpParser",
                +    .function = {
                +      .dmark = HttpParser_mark,
                +      .dfree = RUBY_TYPED_DEFAULT_FREE,
                +      .dsize = HttpParser_size,
                +      .dcompact = HttpParser_compact,
                +    },
                +    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
                @@ -294 +288 @@
                -VALUE HttpParser_alloc(VALUE klass)
                +static VALUE HttpParser_alloc(VALUE klass)
                @@ -297 +290,0 @@
                -  TRACE();
                @@ -312,0 +306,10 @@
                +static inline puma_parser *HttpParser_unwrap(VALUE self)
                +{
                +  puma_parser *http;
                +  TypedData_Get_Struct(self, puma_parser, &HttpParser_data_type, http);
                +  if (http == NULL) {
                +    rb_raise(rb_eArgError, "%s", "NULL http_parser found");
                +  }
                +  return http;
                +}
                +
                @@ -319 +322 @@
                -VALUE HttpParser_init(VALUE self)
                +static VALUE HttpParser_init(VALUE self)
                @@ -321,2 +324 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -336 +338 @@
                -VALUE HttpParser_reset(VALUE self)
                +static VALUE HttpParser_reset(VALUE self)
                @@ -338,2 +340 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -353 +354 @@
                -VALUE HttpParser_finish(VALUE self)
                +static VALUE HttpParser_finish(VALUE self)
                @@ -355,2 +356 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -380 +380 @@
                -VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                +static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                @@ -382 +382 @@
                -  puma_parser *http = NULL;
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -387,2 +386,0 @@
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                -
                @@ -390 +388 @@
                -  dptr = rb_extract_chars(data, &dlen);
                +  RSTRING_GETMEM(data, dptr, dlen);
                @@ -393 +390,0 @@
                -    rb_free_chars(dptr);
                @@ -399 +395,0 @@
                -    rb_free_chars(dptr);
                @@ -418 +414 @@
                -VALUE HttpParser_has_error(VALUE self)
                +static VALUE HttpParser_has_error(VALUE self)
                @@ -420,2 +416 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -433 +428 @@
                -VALUE HttpParser_is_finished(VALUE self)
                +static VALUE HttpParser_is_finished(VALUE self)
                @@ -435,2 +430 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -449 +443 @@
                -VALUE HttpParser_nread(VALUE self)
                +static VALUE HttpParser_nread(VALUE self)
                @@ -451,2 +445 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -463,3 +456,2 @@
                -VALUE HttpParser_body(VALUE self) {
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +static VALUE HttpParser_body(VALUE self) {
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -474 +466 @@
                -void Init_puma_http11(void)
                +RUBY_FUNC_EXPORTED void Init_puma_http11(void)
        lib/puma/app/status.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/app/status.rb	2026-01-22 03:33:13.620412663 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/app/status.rb	2026-01-22 03:33:13.632412644 +0000
                @@ -9,0 +10 @@
                +      READ_ONLY_COMMANDS = %w[gc-stats stats].freeze
                @@ -12,0 +14 @@
                +      # @param data_only [Boolean] if true, restrict to read-only data commands
                @@ -14 +16 @@
                -      def initialize(launcher, token = nil)
                +      def initialize(launcher, token: nil, data_only: false)
                @@ -16,0 +19 @@
                +        @enabled_commands = READ_ONLY_COMMANDS if data_only
                @@ -27,0 +31,5 @@
                +        command = env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +        if @enabled_commands && !@enabled_commands.include?(command)
                +          return rack_response(404, "Command #{command.inspect} unavailable", 'text/plain')
                +        end
                +
                @@ -29 +37 @@
                -          case env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +          case command
        lib/puma/cluster.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/cluster.rb	2026-01-22 03:33:13.621412661 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/cluster.rb	2026-01-22 03:33:13.633412643 +0000
                @@ -189 +189 @@
                -        w = @workers.find { |x| x.phase != @phase }
                +        w = @workers.find { |x| x.phase < @phase }
                @@ -224 +223,0 @@
                -      server = start_server if preload?
                @@ -229 +228 @@
                -                              server: server
                +                              app: (app if preload?)
        lib/puma/cluster/worker.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:13.621412661 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:13.633412643 +0000
                @@ -17 +17 @@
                -      def initialize(index:, master:, launcher:, pipes:, server: nil)
                +      def initialize(index:, master:, launcher:, pipes:, app: nil)
                @@ -26 +26,2 @@
                -        @server = server
                +        @app = app
                +        @server = nil
                @@ -60 +61 @@
                -        server = @server ||= start_server
                +          @server = start_server
                @@ -88 +89 @@
                -                  server.begin_restart(true)
                +                  @server.begin_restart(true)
                @@ -106 +107 @@
                -          server.stop
                +          @server.stop
                @@ -118 +119 @@
                -          server_thread = server.run
                +          server_thread = @server.run
                @@ -132 +133 @@
                -                hsh = server.stats
                +                hsh = @server.stats
                @@ -138 +139 @@
                -                server.reset_max
                +                @server.reset_max
                @@ -167 +168 @@
                -                                  server: @server
                +                                  app: @app
        lib/puma/configuration.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/configuration.rb	2026-01-22 03:33:13.622412660 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/configuration.rb	2026-01-22 03:33:13.634412641 +0000
                @@ -200 +200 @@
                -    attr_reader :plugins, :events, :hooks
                +    attr_reader :plugins, :events, :hooks, :_options
                @@ -241,6 +241,2 @@
                -      workers = if env['WEB_CONCURRENCY'] == 'auto'
                -        require_processor_counter
                -        ::Concurrent.available_processor_count
                -      else
                -        env['WEB_CONCURRENCY']
                -      end
                +      workers_env = env['WEB_CONCURRENCY']
                +      workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
                @@ -252 +248 @@
                -        workers: workers && workers != "" && Integer(workers),
                +        workers: workers,
                @@ -383 +379 @@
                -        WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
                +        WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
                @@ -386,0 +383,11 @@
                +    end
                +
                +    def parse_workers(value)
                +      if value == :auto || value == 'auto'
                +        require_processor_counter
                +        Integer(::Concurrent.available_processor_count)
                +      else
                +        Integer(value)
                +      end
                +    rescue ArgumentError, TypeError
                +      raise ArgumentError, "workers must be an Integer or :auto"
        lib/puma/const.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/const.rb	2026-01-22 03:33:13.622412660 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/const.rb	2026-01-22 03:33:13.634412641 +0000
                @@ -103,2 +103,2 @@
                -    PUMA_VERSION = VERSION = "7.1.0"
                -    CODE_NAME = "Neon Witch"
                +    PUMA_VERSION = VERSION = "7.2.0"
                +    CODE_NAME = "On The Corner"
        lib/puma/dsl.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/dsl.rb	2026-01-22 03:33:13.622412660 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/dsl.rb	2026-01-22 03:33:13.634412641 +0000
                @@ -218,0 +219,2 @@
                +    # @example
                +    #   activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
                @@ -242,0 +245 @@
                +      @options[:control_data_only] = opts[:data_only] if opts[:data_only]
                @@ -669,2 +672,2 @@
                -    # How many worker processes to run.  Typically this is set to
                -    # the number of available cores.
                +    # How many worker processes to run. Typically this is set to the number of
                +    # available cores.
                @@ -673 +676,6 @@
                -    # set, otherwise 0.
                +    # set, otherwise 0. Passing +:auto+ will set the value to
                +    # +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
                +    # On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
                +    # will round down. If it rounds down to 0, Puma will run in single mode and
                +    # cluster-only hooks like +before_worker_boot+ will not execute.
                +    # If you rely on cluster-only hooks, set an explicit worker count.
                @@ -675 +683 @@
                -    # @note Cluster mode only.
                +    # A value of 0 or nil means run in single mode.
                @@ -678,0 +687 @@
                +    #   workers :auto
                @@ -683 +692 @@
                -      @options[:workers] = count.to_i
                +      @options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
                @@ -997,0 +1007 @@
                +    # @note When using `fork_worker`, this only applies to worker 0.
                @@ -1381 +1391 @@
                -    # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
                +    # @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
        lib/puma/launcher.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/launcher.rb	2026-01-22 03:33:13.623412658 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/launcher.rb	2026-01-22 03:33:13.635412640 +0000
                @@ -45 +45 @@
                -      ## Minimal initialization for a potential early restart (e.g. when pruning bundle)
                +      ## Minimal initialization before potential early restart (e.g. from bundle pruning)
                @@ -47,0 +48,2 @@
                +      # Advertise the CLI Configuration before config files are loaded
                +      Puma.cli_config = @config if defined?(Puma.cli_config)
                @@ -73,2 +75 @@
                -      # Advertise the Configuration
                -      Puma.cli_config = @config if defined?(Puma.cli_config)
                +      # Log after prune_bundler! to avoid duplicate logging if a restart occurs
        lib/puma/reactor.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/reactor.rb	2026-01-22 03:33:13.624412657 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/reactor.rb	2026-01-22 03:33:13.636412638 +0000
                @@ -78 +77,0 @@
                -      close_selector = true
                @@ -84 +82,0 @@
                -          monitor_wake_up = false
                @@ -86 +83,0 @@
                -            monitor_wake_up = true
                @@ -106,8 +103 @@
                -        # NoMethodError may be rarely raised when calling @selector.select, which
                -        # is odd.  Regardless, it may continue for thousands of calls if retried.
                -        # Also, when it raises, @selector.close also raises an error.
                -        if !monitor_wake_up && NoMethodError === e
                -          close_selector = false
                -        else
                -          retry
                -        end
                +        retry
                @@ -114,0 +105 @@
                +
                @@ -117 +108 @@
                -      @selector.close if close_selector
                +      @selector.close
        lib/puma/request.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/request.rb	2026-01-22 03:33:13.624412657 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/request.rb	2026-01-22 03:33:13.637412637 +0000
                @@ -39 +39 @@
                -    # It'll return +false+ when the connection is closed, this doesn't mean
                +    # It'll return +:close+ when the connection is closed, this doesn't mean
                @@ -41,0 +42,3 @@
                +    # It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
                +    # Which may contain additional requests.
                +    #
                @@ -48,2 +51 @@
                -    # @return [Boolean,:async]
                -    #
                +    # @return [:close, :keep_alive, :async]
                @@ -57 +59 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -170 +172 @@
                -    # @return [Boolean,:async] keep-alive status or `:async`
                +    # @return [:close, :keep_alive, :async]
                @@ -176 +178 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -247 +249 @@
                -          return keep_alive
                +          return keep_alive ? :keep_alive : :close
                @@ -273 +275 @@
                -      !shutting_down? && keep_alive
                +      !shutting_down? && keep_alive ? :keep_alive : :close
        lib/puma/runner.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/runner.rb	2026-01-22 03:33:13.625412655 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/runner.rb	2026-01-22 03:33:13.637412637 +0000
                @@ -73 +73 @@
                -      app = Puma::App::Status.new @launcher, token
                +      app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
        lib/puma/server.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/server.rb	2026-01-22 03:33:13.625412655 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/server.rb	2026-01-22 03:33:13.637412637 +0000
                @@ -302 +302 @@
                -    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).
                +    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
                @@ -504 +504 @@
                -          when false
                +          when :close
                @@ -507 +507 @@
                -          when true
                +          when :keep_alive
        lib/puma/single.rb
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/lib/puma/single.rb	2026-01-22 03:33:13.625412655 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/lib/puma/single.rb	2026-01-22 03:33:13.637412637 +0000
                @@ -52,2 +52,2 @@
                -      @server = server = start_server
                -      server_thread = server.run
                +      @server = start_server
                +      server_thread = @server.run
        tools/Dockerfile
                --- /tmp/d20260122-626-fxn6gi/puma-7.1.0/tools/Dockerfile	2026-01-22 03:33:13.626412654 +0000
                +++ /tmp/d20260122-626-fxn6gi/puma-7.2.0/tools/Dockerfile	2026-01-22 03:33:13.638412635 +0000
                @@ -1,0 +2,2 @@
                +# Build (MRI): docker build -f tools/Dockerfile .
                +# Build (JRuby): docker build -f tools/Dockerfile --build-arg RUBY_IMAGE=jruby:9.4 .
                @@ -3 +5,2 @@
                -FROM ruby:3.2
                +ARG RUBY_IMAGE=ruby:latest
                +FROM ${RUBY_IMAGE}
                @@ -5 +8,2 @@
                -RUN apt-get update && apt-get install -y ragel
                +# Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
                +ARG BUNDLE_FROZEN=true
                @@ -7,2 +11,6 @@
                -# throw errors if Gemfile has been modified since Gemfile.lock
                -RUN bundle config --global frozen 1
                +RUN apt-get update \
                +  && apt-get install -y --no-install-recommends ragel procps git \
                +  && rm -rf /var/lib/apt/lists/*
                +
                +# Only freeze Bundler and compile native extensions when using MRI.
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ] && [ "${BUNDLE_FROZEN}" = "true" ]; then bundle config --global frozen 1; fi
                @@ -15 +23 @@
                -RUN bundle exec rake compile
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi

@github-actions
Copy link
Contributor

gem compare puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT metadata:
    7.1.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/master/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
    7.2.0: {"bug_tracker_uri" => "https://github.com/puma/puma/issues", "changelog_uri" => "https://github.com/puma/puma/blob/main/History.md", "homepage_uri" => "https://puma.io", "source_code_uri" => "https://github.com/puma/puma", "rubygems_mfa_required" => "true", "msys2_mingw_dependencies" => "openssl"}
  DIFFERENT require_paths:
    7.1.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.1.0", "lib"]
    7.2.0: ["/opt/hostedtoolcache/Ruby/4.0.1/x64/lib/ruby/gems/4.0.0/extensions/x86_64-linux/4.0.0/puma-7.2.0", "lib"]
  DIFFERENT rubygems_version:
    7.1.0: 3.6.9
    7.2.0: 4.0.3
  DIFFERENT version:
    7.1.0: 7.1.0
    7.2.0: 7.2.0
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
            History.md +71/-0
            README.md +17/-9
            docs/deployment.md +58/-23
            docs/jungle/README.md +1/-1
            docs/kubernetes.md +3/-10
            docs/plugins.md +2/-2
            docs/signals.md +10/-10
            docs/stats.md +1/-1
            docs/systemd.md +3/-3
            ext/puma_http11/puma_http11.c +101/-109
            lib/puma/app/status.rb +10/-2
            lib/puma/cluster.rb +2/-3
            lib/puma/cluster/worker.rb +10/-9
            lib/puma/configuration.rb +16/-9
            lib/puma/const.rb +2/-2
            lib/puma/dsl.rb +16/-6
            lib/puma/launcher.rb +4/-3
            lib/puma/reactor.rb +3/-12
            lib/puma/request.rb +10/-8
            lib/puma/runner.rb +1/-1
            lib/puma/server.rb +3/-3
            lib/puma/single.rb +2/-2
            tools/Dockerfile +13/-5

@github-actions
Copy link
Contributor

gem compare --diff puma 7.1.0 7.2.0

Compared versions: ["7.1.0", "7.2.0"]
  DIFFERENT files:
    7.1.0->7.2.0:
      * Deleted:
            ext/puma_http11/ext_help.h
      * Changed:
        History.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/History.md	2026-01-22 03:33:52.082391487 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/History.md	2026-01-22 03:33:52.094391659 +0000
                @@ -0,0 +1,35 @@
                +## 7.2.0 / 2026-01-20
                +
                +* Features
                +  * Add workers `:auto` ([#3827])
                +  * Make it possible to restrict control server commands to stats ([#3787])
                +
                +* Bugfixes
                +  * Don't break if `WEB_CONCURRENCY` is set to a blank string ([#3837])
                +  * Don't share server between worker 0 and descendants on refork ([#3602])
                +  * Fix phase check race condition in `Puma::Cluster#check_workers` ([#3690])
                +  * Fix advertising of CLI config before config files are loaded ([#3823])
                +
                +* Performance
                +  * 17% faster HTTP parsing through pre-interning env keys ([#3825])
                +  * Implement `dsize` and `dcompact` functions for `Puma::HttpParser`, which makes Puma's C-extension GC-compactible ([#3828])
                +
                +* Refactor
                +  * Remove `NoMethodError` rescue in `Reactor#select_loop` ([#3831])
                +  * Various cleanups in the C extension ([#3814])
                +  * Monomorphize `handle_request` return ([#3802])
                +
                +* Docs
                +  * Change link to `docs/deployment.md` in `README.md` ([#3848])
                +  * Fix formatting for each signal description in signals.md ([#3813])
                +  * Update deployment and Kubernetes docs with Puma configuration tips ([#3807])
                +  * Rename master to main ([#3809], [#3808], [#3800])
                +  * Fix some minor typos in the docs ([#3804])
                +  * Add `GOVERNANCE.md`, `MAINTAINERS` ([#3826])
                +  * Remove Code Climate badge ([#3820])
                +  * Add @joshuay03 to the maintainer list
                +
                +* CI
                +  * Use Minitest 6 where applicable ([#3859])
                +  * Many test suite improvements and flake fixes ([#3861], [#3863], [#3860], [#3852], [#3857], [#3856], [#3845], [#3843], [#3842], [#3841], [#3822], [#3817], [#3764])
                +
                @@ -2260,0 +2296,36 @@
                +
                +[#3863]:https://github.com/puma/puma/pull/3863     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3861]:https://github.com/puma/puma/pull/3861     "PR by MSP-Greg, merged 2026-01-20"
                +[#3860]:https://github.com/puma/puma/pull/3860     "PR by MSP-Greg, merged 2026-01-16"
                +[#3859]:https://github.com/puma/puma/pull/3859     "PR by MSP-Greg, merged 2026-01-16"
                +[#3857]:https://github.com/puma/puma/pull/3857     "PR by Aaron Patterson, merged 2026-01-12"
                +[#3856]:https://github.com/puma/puma/pull/3856     "PR by MSP-Greg, merged 2026-01-12"
                +[#3852]:https://github.com/puma/puma/pull/3852     "PR by Miłosz Bieniek, merged 2026-01-14"
                +[#3848]:https://github.com/puma/puma/pull/3848     "PR by Miłosz Bieniek, merged 2025-12-27"
                +[#3845]:https://github.com/puma/puma/pull/3845     "PR by MSP-Greg, merged 2025-12-19"
                +[#3843]:https://github.com/puma/puma/pull/3843     "PR by MSP-Greg, merged 2025-12-18"
                +[#3842]:https://github.com/puma/puma/pull/3842     "PR by MSP-Greg, merged 2025-12-18"
                +[#3841]:https://github.com/puma/puma/pull/3841     "PR by MSP-Greg, merged 2025-12-18"
                +[#3837]:https://github.com/puma/puma/pull/3837     "PR by John Bachir, merged 2026-01-09"
                +[#3833]:https://github.com/puma/puma/pull/3833     "PR by Patrik Ragnarsson, merged 2025-11-25"
                +[#3831]:https://github.com/puma/puma/pull/3831     "PR by Joshua Young, merged 2025-11-25"
                +[#3828]:https://github.com/puma/puma/pull/3828     "PR by Jean Boussier, merged 2025-11-21"
                +[#3827]:https://github.com/puma/puma/pull/3827     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3826]:https://github.com/puma/puma/pull/3826     "PR by Nate Berkopec, merged 2026-01-20"
                +[#3825]:https://github.com/puma/puma/pull/3825     "PR by Jean Boussier, merged 2025-11-19"
                +[#3823]:https://github.com/puma/puma/pull/3823     "PR by Joshua Young, merged 2025-11-18"
                +[#3822]:https://github.com/puma/puma/pull/3822     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3820]:https://github.com/puma/puma/pull/3820     "PR by Nate Berkopec, merged 2025-11-19"
                +[#3817]:https://github.com/puma/puma/pull/3817     "PR by Nate Berkopec, merged 2025-11-17"
                +[#3814]:https://github.com/puma/puma/pull/3814     "PR by Jean Boussier, merged 2025-11-17"
                +[#3813]:https://github.com/puma/puma/pull/3813     "PR by Masafumi Koba, merged 2025-11-17"
                +[#3809]:https://github.com/puma/puma/pull/3809     "PR by Patrik Ragnarsson, merged 2025-10-26"
                +[#3808]:https://github.com/puma/puma/pull/3808     "PR by Nymuxyzo, merged 2025-10-26"
                +[#3807]:https://github.com/puma/puma/pull/3807     "PR by Nate Berkopec, merged 2025-10-28"
                +[#3804]:https://github.com/puma/puma/pull/3804     "PR by Joe Rafaniello, merged 2025-10-21"
                +[#3802]:https://github.com/puma/puma/pull/3802     "PR by Richard Schneeman, merged 2025-10-20"
                +[#3800]:https://github.com/puma/puma/pull/3800     "PR by MSP-Greg, merged 2025-10-19"
                +[#3787]:https://github.com/puma/puma/pull/3787     "PR by Stan Hu, merged 2025-10-17"
                +[#3764]:https://github.com/puma/puma/pull/3764     "PR by MSP-Greg, merged 2025-10-17"
                +[#3690]:https://github.com/puma/puma/pull/3690     "PR by Joshua Young, merged 2025-11-18"
                +[#3602]:https://github.com/puma/puma/pull/3602     "PR by Joshua Young, merged 2025-11-28"
        README.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/README.md	2026-01-22 03:33:52.082391487 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/README.md	2026-01-22 03:33:52.095391673 +0000
                @@ -7,2 +7 @@
                -[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amaster)
                -[![Code Climate](https://codeclimate.com/github/puma/puma.svg)](https://codeclimate.com/github/puma/puma)
                +[![Actions](https://github.com/puma/puma/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/puma/puma/actions/workflows/tests.yml?query=branch%3Amain)
                @@ -85 +84 @@
                -Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb).
                +Puma provides numerous options. Consult `puma -h` (or `puma --help`) for a full list of CLI options, or see `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb).
                @@ -88 +87 @@
                -[test](https://github.com/puma/puma/tree/master/test/config) suite.
                +[test](https://github.com/puma/puma/tree/main/test/config) suite.
                @@ -118,0 +118,9 @@
                +When using a config file, most applications can simply set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of worker processes to the available processors:
                +
                +```ruby
                +# config/puma.rb
                +workers :auto
                +```
                +
                +See [`workers :auto` gotchas](lib/puma/dsl.rb).
                +
                @@ -121 +129 @@
                -If the `WEB_CONCURRENCY` environment variable is set to `"auto"` and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent.html#available_processor_count-class_method).
                +If `workers` is set to `:auto`, or the `WEB_CONCURRENCY` environment variable is set to `"auto"`, and the `concurrent-ruby` gem is available in your application, Puma will set the worker process count to the result of [available processors](https://msp-greg.github.io/concurrent-ruby/Concurrent.html#available_processor_count-class_method).
                @@ -123 +131 @@
                -For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](https://github.com/puma/puma/blob/9282a8efa5a0c48e39c60d22ca70051a25df9f55/docs/kubernetes.md#workers-per-pod-and-other-config-issues).
                +For an in-depth discussion of the tradeoffs of thread and process count settings, [see our docs](docs/deployment.md).
                @@ -229 +237 @@
                -textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/master/lib/puma/server.rb)).
                +textual error message (see `Puma::Server#lowlevel_error` or [server.rb](https://github.com/puma/puma/blob/main/lib/puma/server.rb)).
                @@ -388 +396 @@
                -Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/master/lib/puma/app/status.rb) to see what the status app has available.
                +Puma will start the control server on localhost port 9293. All requests to the control server will need to include control token (in this case, `token=foo`) as a query parameter. This allows for simple authentication. Check out `Puma::App::Status` or [status.rb](https://github.com/puma/puma/blob/main/lib/puma/app/status.rb) to see what the status app has available.
                @@ -420 +428 @@
                -Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/master/lib/puma/dsl.rb) to see all available options.
                +Check out `Puma::DSL` or [dsl.rb](https://github.com/puma/puma/blob/main/lib/puma/dsl.rb) to see all available options.
        docs/deployment.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/deployment.md	2026-01-22 03:33:52.083391501 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/deployment.md	2026-01-22 03:33:52.095391673 +0000
                @@ -18,0 +19,7 @@
                +In general, use single mode only if:
                +
                +* You are using JRuby, TruffleRuby or another fully-multithreaded implementation of Ruby
                +* You are using MRI but in an environment where only 1 CPU core is available.
                +
                +Otherwise, you'll want to use cluster mode to utilize all available CPU resources.
                +
                @@ -22 +29 @@
                -Here are some tips for cluster mode:
                +## Cluster Mode Tips
                @@ -24 +31 @@
                -### MRI
                +For the purposes of Puma provisioning, "CPU cores" means:
                @@ -26,4 +33,2 @@
                -* Use cluster mode and set the number of workers to 1.5x the number of CPU cores
                -  in the machine, starting from a minimum of 2.
                -* Set the number of threads to desired concurrent requests/number of workers.
                -  Puma defaults to 5, and that's a decent number.
                +1. On ARM, the number of physical cores.
                +2. On x86, the number of logical cores, hyperthreads, or vCPUs (these words all mean the same thing).
                @@ -31 +36 @@
                -#### Migrating from Unicorn
                +Set your config with the following process:
                @@ -33,6 +38,3 @@
                -* If you're migrating from unicorn though, here are some settings to start with:
                -  * Set workers to half the number of unicorn workers you're using
                -  * Set threads to 2
                -  * Enjoy 50% memory savings
                -* As you grow more confident in the thread-safety of your app, you can tune the
                -  workers down and the threads up.
                +* Use cluster mode and set `workers :auto` (requires the `concurrent-ruby` gem) to match the number of CPU cores on the machine (minimum 2, otherwise use single mode!). If you can't add the gem, set the worker count manually to the available CPU cores.
                +* Set the number of threads to desired concurrent requests/number of workers.
                +  Puma defaults to 5, and that's a decent number.
                @@ -40 +42 @@
                -#### Ubuntu / Systemd (Systemctl) Installation
                +For most deployments, adding `concurrent-ruby` and using `workers :auto` is the right starting point.
                @@ -42 +44 @@
                -See [systemd.md](systemd.md)
                +See [`workers :auto` gotchas](../lib/puma/dsl.rb).
                @@ -44 +46 @@
                -#### Worker utilization
                +## Worker utilization
                @@ -53,3 +55,9 @@
                -there is more work to do than the process can get through. On the other hand, if
                -you have processes that sit around doing nothing, then they're just eating up
                -resources.
                +there is more work to do than the process can get through, and requests will end up with additional latency. On the other hand, if
                +you have processes that sit around doing nothing, then you're wasting resources and money.
                +
                +In general, you are making a tradeoff between:
                +
                +1. CPU and memory utilization.
                +2. Time spent queueing for a Puma worker to `accept` requests and additional latency caused by CPU contention.
                +
                +If latency is important to you, you will have to accept lower utilization, and vice versa.
                @@ -57,2 +65 @@
                -Watch your CPU utilization over time and aim for about 70% on average. 70%
                -utilization means you've got capacity still but aren't starving threads.
                +## Container/VPS sizing
                @@ -60 +67,16 @@
                -**Measuring utilization**
                +You will have to make a decision about how "big" to make each pod/VPS/server/dyno.
                +
                +**TL:DR;**: 80% of Puma apps will end up deploying "pods" of 4 workers, 5 threads each, 4 vCPU and 8GB of RAM.
                +
                +For the rest of this discussion, we'll adopt the Kubernetes term of "pods".
                +
                +Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make:
                +
                +* **Increasing worker counts decreases latency, but means you scale in bigger "chunks"**. Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                +* **Increasing thread counts will increase throughput, but also latency and memory use** Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50% of wall clock time) will lead to additional request latency and additional memory usage.
                +* **Increasing worker counts decreases memory per worker on average**. More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                +* **Low worker counts (<4) have exceptionally poor throughput**. Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing (see discussion above), which means you will have to run more pods and resources.
                +* **CPU-core-to-worker ratios should be around 1**. If running Puma with `threads > 1`, allocate 1 CPU core (see definition above!) per worker. If single threaded, allocate ~0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core. Using `workers :auto` will size workers to this guidance on most platforms.
                +* **Don't set memory limits unless necessary**. Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +
                +**Measuring utilization and queue time**
                @@ -78 +100 @@
                -      can can also be added as headers.
                +      can also be added as headers.
                @@ -102,0 +125,13 @@
                +
                +## Migrating from Unicorn
                +
                +* If you're migrating from unicorn though, here are some settings to start with:
                +  * Set workers to half the number of unicorn workers you're using
                +  * Set threads to 2
                +  * Enjoy 50% memory savings
                +* As you grow more confident in the thread-safety of your app, you can tune the
                +  workers down and the threads up.
                +
                +## Ubuntu / Systemd (Systemctl) Installation
                +
                +See [systemd.md](systemd.md)
        docs/jungle/README.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/jungle/README.md	2026-01-22 03:33:52.083391501 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/jungle/README.md	2026-01-22 03:33:52.096391687 +0000
                @@ -5 +5 @@
                -See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
                +See [/docs/systemd](https://github.com/puma/puma/blob/main/docs/systemd.md).
        docs/kubernetes.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/kubernetes.md	2026-01-22 03:33:52.084391516 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/kubernetes.md	2026-01-22 03:33:52.097391702 +0000
                @@ -5 +5 @@
                -In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some request might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                +In general running Puma in Kubernetes works as-is, no special configuration is needed beyond what you would write anyway to get a new Kubernetes Deployment going. There is one known interaction between the way Kubernetes handles pod termination and how Puma handles `SIGINT`, where some requests might be sent to Puma after it has already entered graceful shutdown mode and is no longer accepting requests. This can lead to dropped requests during rolling deploys. A workaround for this is listed at the end of this article.
                @@ -64 +64 @@
                -There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives this request handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                +There is a subtle race condition between step 2 and 3: The replication controller does not synchronously remove the pod from the Services AND THEN call the pre-stop hook of the pod, but rather it asynchronously sends "remove this pod from your endpoints" requests to the Services and then immediately proceeds to invoke the pods' pre-stop hook. If the Service controller (typically something like nginx or haproxy) receives and handles this request "too" late (due to internal lag or network latency between the replication and Service controllers) then it is possible that the Service controller will send one or more requests to a Puma process which has already shut down its listening socket. These requests will then fail with 5XX error codes.
                @@ -72,8 +72 @@
                -With containerization, you will have to make a decision about how "big" to make each pod. Should you run 2 pods with 50 workers each? 25 pods, each with 4 workers? 100 pods, with each Puma running in single mode? Each scenario represents the same total amount of capacity (100 Puma processes that can respond to requests), but there are tradeoffs to make.
                -
                -* Worker counts should be somewhere between 4 and 32 in most cases. You want more than 4 in order to minimize time spent in request queueing for a free Puma worker, but probably less than ~32 because otherwise autoscaling is working in too large of an increment or they probably won't fit very well into your nodes. In any queueing system, queue time is proportional to 1/n, where n is the number of things pulling from the queue. Each pod will have its own request queue (i.e., the socket backlog). If you have 4 pods with 1 worker each (4 request queues), wait times are, proportionally, about 4 times higher than if you had 1 pod with 4 workers (1 request queue).
                -* Unless you have a very I/O-heavy application (50%+ time spent waiting on IO), use the default thread count (5 for MRI). Using higher numbers of threads with low I/O wait (<50%) will lead to additional request queueing time (latency!) and additional memory usage.
                -* More processes per pod reduces memory usage per process, because of copy-on-write memory and because the cost of the single master process is "amortized" over more child processes.
                -* Don't run less than 4 processes per pod if you can. Low numbers of processes per pod will lead to high request queueing, which means you will have to run more pods.
                -* If multithreaded, allocate 1 CPU per worker. If single threaded, allocate 0.75 cpus per worker. Most web applications spend about 25% of their time in I/O - but when you're running multi-threaded, your Puma process will have higher CPU usage and should be able to fully saturate a CPU core.
                -* Most Puma processes will use about ~512MB-1GB per worker, and about 1GB for the master process. However, you probably shouldn't bother with setting memory limits lower than around 2GB per process, because most places you are deploying will have 2GB of RAM per CPU. A sensible memory limit for a Puma configuration of 4 child workers might be something like 8 GB (1 GB for the master, 7GB for the 4 children).
                +See our [deployment docs](./deployment.md) for more information about how to correctly size your pods and choose the right number of workers and threads.
        docs/plugins.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/plugins.md	2026-01-22 03:33:52.084391516 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/plugins.md	2026-01-22 03:33:52.097391702 +0000
                @@ -8 +8 @@
                -* [tmp\_restart](https://github.com/puma/puma/blob/master/lib/puma/plugin/tmp_restart.rb):
                +* [tmp\_restart](https://github.com/puma/puma/blob/main/lib/puma/plugin/tmp_restart.rb):
                @@ -14 +14 @@
                -Plugins are activated in a Puma configuration file (such as `config/puma.rb'`)
                +Plugins are activated in a Puma configuration file (such as `config/puma.rb`)
        docs/signals.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/signals.md	2026-01-22 03:33:52.084391516 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/signals.md	2026-01-22 03:33:52.097391702 +0000
                @@ -36,10 +36,10 @@
                -- `TTIN` increment the worker count by 1
                -- `TTOU` decrement the worker count by 1
                -- `TERM` send `TERM` to worker. The worker will attempt to finish then exit.
                -- `USR2` restart workers. This also reloads the Puma configuration file, if there is one.
                -- `USR1` restart workers in phases, a rolling restart. This will not reload the configuration file.
                -- `HUP ` reopen log files defined in stdout_redirect configuration parameter. If there is no stdout_redirect option provided, it will behave like `INT`
                -- `INT ` equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                -- `CHLD`
                -- `URG ` refork workers in phases from worker 0 if `fork_workers` option is enabled.
                -- `INFO` print backtraces of all puma threads
                +- `TTIN`: Increment the worker count by 1.
                +- `TTOU`: Decrement the worker count by 1.
                +- `TERM`: Send `TERM` to worker. The worker will attempt to finish then exit.
                +- `USR2`: Restart workers. This also reloads the Puma configuration file, if there is one.
                +- `USR1`: Restart workers in phases, a rolling restart. This will not reload the configuration file.
                +- `HUP`:  Reopen log files defined in `stdout_redirect` configuration parameter. If there is no `stdout_redirect` option provided, it will behave like `INT`.
                +- `INT`:  Equivalent of sending Ctrl-C to cluster. Puma will attempt to finish then exit.
                +- `CHLD`: Reap zombie child processes and wake event loop in `fork_worker` mode.
                +- `URG`:  Refork workers in phases from worker 0 if `fork_worker` option is enabled.
                +- `INFO`: Print backtraces of all Puma threads.
        docs/stats.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/stats.md	2026-01-22 03:33:52.084391516 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/stats.md	2026-01-22 03:33:52.097391702 +0000
                @@ -73 +73 @@
                -* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/master/docs/restart.md)
                +* phase: which phase of restart the process is in, during [phased restart](https://github.com/puma/puma/blob/main/docs/restart.md)
        docs/systemd.md
                --- /tmp/d20260122-667-htboom/puma-7.1.0/docs/systemd.md	2026-01-22 03:33:52.085391530 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/docs/systemd.md	2026-01-22 03:33:52.097391702 +0000
                @@ -122,2 +122,2 @@
                -folder path (ex. `/srv/projet/shared/tmp/puma.sock`), not the release folder
                -path (`/srv/projet/releases/1234/tmp/puma.sock`).
                +folder path (ex. `/srv/project/shared/tmp/puma.sock`), not the release folder
                +path (`/srv/project/releases/1234/tmp/puma.sock`).
                @@ -142 +142 @@
                -binds that's not socket activated.
                +binds that are not socket activated.
        ext/puma_http11/puma_http11.c
                --- /tmp/d20260122-667-htboom/puma-7.1.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:52.087391559 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/ext/puma_http11/puma_http11.c	2026-01-22 03:33:52.099391730 +0000
                @@ -11 +10,0 @@
                -#include "ext_help.h"
                @@ -17,13 +16 @@
                -#ifndef MANAGED_STRINGS
                -
                -#ifndef RSTRING_PTR
                -#define RSTRING_PTR(s) (RSTRING(s)->ptr)
                -#endif
                -#ifndef RSTRING_LEN
                -#define RSTRING_LEN(s) (RSTRING(s)->len)
                -#endif
                -
                -#define rb_extract_chars(e, sz) (*sz = RSTRING_LEN(e), RSTRING_PTR(e))
                -#define rb_free_chars(e) /* nothing */
                -
                -#endif
                +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
                @@ -54,2 +41,2 @@
                -    rb_global_variable(var);
                -    *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                +  rb_global_variable(var);
                +  *var = rb_enc_interned_str_cstr(cstr, rb_utf8_encoding());
                @@ -80,2 +67,2 @@
                -	const size_t len;
                -	const char *name;
                +  const size_t len;
                +  const char *name;
                @@ -83 +70 @@
                -	VALUE value;
                +  VALUE value;
                @@ -94,36 +81,36 @@
                -	f("ACCEPT"),
                -	f("ACCEPT_CHARSET"),
                -	f("ACCEPT_ENCODING"),
                -	f("ACCEPT_LANGUAGE"),
                -	f("ALLOW"),
                -	f("AUTHORIZATION"),
                -	f("CACHE_CONTROL"),
                -	f("CONNECTION"),
                -	f("CONTENT_ENCODING"),
                -	fr("CONTENT_LENGTH"),
                -	fr("CONTENT_TYPE"),
                -	f("COOKIE"),
                -	f("DATE"),
                -	f("EXPECT"),
                -	f("FROM"),
                -	f("HOST"),
                -	f("IF_MATCH"),
                -	f("IF_MODIFIED_SINCE"),
                -	f("IF_NONE_MATCH"),
                -	f("IF_RANGE"),
                -	f("IF_UNMODIFIED_SINCE"),
                -	f("KEEP_ALIVE"), /* Firefox sends this */
                -	f("MAX_FORWARDS"),
                -	f("PRAGMA"),
                -	f("PROXY_AUTHORIZATION"),
                -	f("RANGE"),
                -	f("REFERER"),
                -	f("TE"),
                -	f("TRAILER"),
                -	f("TRANSFER_ENCODING"),
                -	f("UPGRADE"),
                -	f("USER_AGENT"),
                -	f("VIA"),
                -	f("X_FORWARDED_FOR"), /* common for proxies */
                -	f("X_REAL_IP"), /* common for proxies */
                -	f("WARNING")
                +  f("ACCEPT"),
                +  f("ACCEPT_CHARSET"),
                +  f("ACCEPT_ENCODING"),
                +  f("ACCEPT_LANGUAGE"),
                +  f("ALLOW"),
                +  f("AUTHORIZATION"),
                +  f("CACHE_CONTROL"),
                +  f("CONNECTION"),
                +  f("CONTENT_ENCODING"),
                +  fr("CONTENT_LENGTH"),
                +  fr("CONTENT_TYPE"),
                +  f("COOKIE"),
                +  f("DATE"),
                +  f("EXPECT"),
                +  f("FROM"),
                +  f("HOST"),
                +  f("IF_MATCH"),
                +  f("IF_MODIFIED_SINCE"),
                +  f("IF_NONE_MATCH"),
                +  f("IF_RANGE"),
                +  f("IF_UNMODIFIED_SINCE"),
                +  f("KEEP_ALIVE"), /* Firefox sends this */
                +  f("MAX_FORWARDS"),
                +  f("PRAGMA"),
                +  f("PROXY_AUTHORIZATION"),
                +  f("RANGE"),
                +  f("REFERER"),
                +  f("TE"),
                +  f("TRAILER"),
                +  f("TRANSFER_ENCODING"),
                +  f("UPGRADE"),
                +  f("USER_AGENT"),
                +  f("VIA"),
                +  f("X_FORWARDED_FOR"), /* common for proxies */
                +  f("X_REAL_IP"), /* common for proxies */
                +  f("WARNING")
                @@ -143 +130 @@
                -      cf->value = rb_str_new(cf->name, cf->len);
                +      cf->value = rb_enc_interned_str(cf->name, cf->len, rb_utf8_encoding());
                @@ -146 +133 @@
                -      cf->value = rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len);
                +      cf->value = rb_enc_interned_str(tmp, HTTP_PREFIX_LEN + cf->len, rb_utf8_encoding());
                @@ -166 +153 @@
                -void http_field(puma_parser* hp, const char *field, size_t flen,
                +static void http_field(puma_parser* hp, const char *field, size_t flen,
                @@ -189 +176 @@
                -    f = rb_str_new(hp->buf, new_size);
                +    f = rb_enc_interned_str(hp->buf, new_size, rb_utf8_encoding());
                @@ -211 +198 @@
                -void request_method(puma_parser* hp, const char *at, size_t length)
                +static void request_method(puma_parser* hp, const char *at, size_t length)
                @@ -219 +206 @@
                -void request_uri(puma_parser* hp, const char *at, size_t length)
                +static void request_uri(puma_parser* hp, const char *at, size_t length)
                @@ -229 +216 @@
                -void fragment(puma_parser* hp, const char *at, size_t length)
                +static void fragment(puma_parser* hp, const char *at, size_t length)
                @@ -239 +226 @@
                -void request_path(puma_parser* hp, const char *at, size_t length)
                +static void request_path(puma_parser* hp, const char *at, size_t length)
                @@ -249 +236 @@
                -void query_string(puma_parser* hp, const char *at, size_t length)
                +static void query_string(puma_parser* hp, const char *at, size_t length)
                @@ -259 +246 @@
                -void server_protocol(puma_parser* hp, const char *at, size_t length)
                +static void server_protocol(puma_parser* hp, const char *at, size_t length)
                @@ -268 +255 @@
                -void header_done(puma_parser* hp, const char *at, size_t length)
                +static void header_done(puma_parser* hp, const char *at, size_t length)
                @@ -274,2 +261,5 @@
                -void HttpParser_free(void *data) {
                -  TRACE();
                +static void HttpParser_mark(void *ptr) {
                +  puma_parser *hp = ptr;
                +  rb_gc_mark_movable(hp->request);
                +  rb_gc_mark_movable(hp->body);
                +}
                @@ -277,3 +267,2 @@
                -  if(data) {
                -    xfree(data);
                -  }
                +static size_t HttpParser_size(const void *ptr) {
                +  return sizeof(puma_parser);
                @@ -282 +271 @@
                -void HttpParser_mark(void *ptr) {
                +static void HttpParser_compact(void *ptr) {
                @@ -284,2 +273,2 @@
                -  if(hp->request) rb_gc_mark(hp->request);
                -  if(hp->body) rb_gc_mark(hp->body);
                +  hp->request = rb_gc_location(hp->request);
                +  hp->body = rb_gc_location(hp->body);
                @@ -288,4 +277,9 @@
                -const rb_data_type_t HttpParser_data_type = {
                -    "HttpParser",
                -    { HttpParser_mark, HttpParser_free, 0 },
                -    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
                +static const rb_data_type_t HttpParser_data_type = {
                +    .wrap_struct_name = "Puma::HttpParser",
                +    .function = {
                +      .dmark = HttpParser_mark,
                +      .dfree = RUBY_TYPED_DEFAULT_FREE,
                +      .dsize = HttpParser_size,
                +      .dcompact = HttpParser_compact,
                +    },
                +    .flags = RUBY_TYPED_FREE_IMMEDIATELY,
                @@ -294 +288 @@
                -VALUE HttpParser_alloc(VALUE klass)
                +static VALUE HttpParser_alloc(VALUE klass)
                @@ -297 +290,0 @@
                -  TRACE();
                @@ -312,0 +306,10 @@
                +static inline puma_parser *HttpParser_unwrap(VALUE self)
                +{
                +  puma_parser *http;
                +  TypedData_Get_Struct(self, puma_parser, &HttpParser_data_type, http);
                +  if (http == NULL) {
                +    rb_raise(rb_eArgError, "%s", "NULL http_parser found");
                +  }
                +  return http;
                +}
                +
                @@ -319 +322 @@
                -VALUE HttpParser_init(VALUE self)
                +static VALUE HttpParser_init(VALUE self)
                @@ -321,2 +324 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -336 +338 @@
                -VALUE HttpParser_reset(VALUE self)
                +static VALUE HttpParser_reset(VALUE self)
                @@ -338,2 +340 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -353 +354 @@
                -VALUE HttpParser_finish(VALUE self)
                +static VALUE HttpParser_finish(VALUE self)
                @@ -355,2 +356 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -380 +380 @@
                -VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                +static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start)
                @@ -382 +382 @@
                -  puma_parser *http = NULL;
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -387,2 +386,0 @@
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                -
                @@ -390 +388 @@
                -  dptr = rb_extract_chars(data, &dlen);
                +  RSTRING_GETMEM(data, dptr, dlen);
                @@ -393 +390,0 @@
                -    rb_free_chars(dptr);
                @@ -399 +395,0 @@
                -    rb_free_chars(dptr);
                @@ -418 +414 @@
                -VALUE HttpParser_has_error(VALUE self)
                +static VALUE HttpParser_has_error(VALUE self)
                @@ -420,2 +416 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -433 +428 @@
                -VALUE HttpParser_is_finished(VALUE self)
                +static VALUE HttpParser_is_finished(VALUE self)
                @@ -435,2 +430 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -449 +443 @@
                -VALUE HttpParser_nread(VALUE self)
                +static VALUE HttpParser_nread(VALUE self)
                @@ -451,2 +445 @@
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -463,3 +456,2 @@
                -VALUE HttpParser_body(VALUE self) {
                -  puma_parser *http = NULL;
                -  DATA_GET(self, puma_parser, &HttpParser_data_type, http);
                +static VALUE HttpParser_body(VALUE self) {
                +  puma_parser *http = HttpParser_unwrap(self);
                @@ -474 +466 @@
                -void Init_puma_http11(void)
                +RUBY_FUNC_EXPORTED void Init_puma_http11(void)
        lib/puma/app/status.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/app/status.rb	2026-01-22 03:33:52.088391573 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/app/status.rb	2026-01-22 03:33:52.100391745 +0000
                @@ -9,0 +10 @@
                +      READ_ONLY_COMMANDS = %w[gc-stats stats].freeze
                @@ -12,0 +14 @@
                +      # @param data_only [Boolean] if true, restrict to read-only data commands
                @@ -14 +16 @@
                -      def initialize(launcher, token = nil)
                +      def initialize(launcher, token: nil, data_only: false)
                @@ -16,0 +19 @@
                +        @enabled_commands = READ_ONLY_COMMANDS if data_only
                @@ -27,0 +31,5 @@
                +        command = env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +        if @enabled_commands && !@enabled_commands.include?(command)
                +          return rack_response(404, "Command #{command.inspect} unavailable", 'text/plain')
                +        end
                +
                @@ -29 +37 @@
                -          case env['PATH_INFO'][/\/([^\/]+)$/, 1]
                +          case command
        lib/puma/cluster.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/cluster.rb	2026-01-22 03:33:52.088391573 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/cluster.rb	2026-01-22 03:33:52.101391759 +0000
                @@ -189 +189 @@
                -        w = @workers.find { |x| x.phase != @phase }
                +        w = @workers.find { |x| x.phase < @phase }
                @@ -224 +223,0 @@
                -      server = start_server if preload?
                @@ -229 +228 @@
                -                              server: server
                +                              app: (app if preload?)
        lib/puma/cluster/worker.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:52.088391573 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/cluster/worker.rb	2026-01-22 03:33:52.101391759 +0000
                @@ -17 +17 @@
                -      def initialize(index:, master:, launcher:, pipes:, server: nil)
                +      def initialize(index:, master:, launcher:, pipes:, app: nil)
                @@ -26 +26,2 @@
                -        @server = server
                +        @app = app
                +        @server = nil
                @@ -60 +61 @@
                -        server = @server ||= start_server
                +          @server = start_server
                @@ -88 +89 @@
                -                  server.begin_restart(true)
                +                  @server.begin_restart(true)
                @@ -106 +107 @@
                -          server.stop
                +          @server.stop
                @@ -118 +119 @@
                -          server_thread = server.run
                +          server_thread = @server.run
                @@ -132 +133 @@
                -                hsh = server.stats
                +                hsh = @server.stats
                @@ -138 +139 @@
                -                server.reset_max
                +                @server.reset_max
                @@ -167 +168 @@
                -                                  server: @server
                +                                  app: @app
        lib/puma/configuration.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/configuration.rb	2026-01-22 03:33:52.089391587 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/configuration.rb	2026-01-22 03:33:52.101391759 +0000
                @@ -200 +200 @@
                -    attr_reader :plugins, :events, :hooks
                +    attr_reader :plugins, :events, :hooks, :_options
                @@ -241,6 +241,2 @@
                -      workers = if env['WEB_CONCURRENCY'] == 'auto'
                -        require_processor_counter
                -        ::Concurrent.available_processor_count
                -      else
                -        env['WEB_CONCURRENCY']
                -      end
                +      workers_env = env['WEB_CONCURRENCY']
                +      workers = workers_env && workers_env.strip != "" ? parse_workers(workers_env.strip) : nil
                @@ -252 +248 @@
                -        workers: workers && workers != "" && Integer(workers),
                +        workers: workers,
                @@ -383 +379 @@
                -        WEB_CONCURRENCY=auto requires the "concurrent-ruby" gem to be installed.
                +        WEB_CONCURRENCY=auto or workers(:auto) requires the "concurrent-ruby" gem to be installed.
                @@ -386,0 +383,11 @@
                +    end
                +
                +    def parse_workers(value)
                +      if value == :auto || value == 'auto'
                +        require_processor_counter
                +        Integer(::Concurrent.available_processor_count)
                +      else
                +        Integer(value)
                +      end
                +    rescue ArgumentError, TypeError
                +      raise ArgumentError, "workers must be an Integer or :auto"
        lib/puma/const.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/const.rb	2026-01-22 03:33:52.089391587 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/const.rb	2026-01-22 03:33:52.101391759 +0000
                @@ -103,2 +103,2 @@
                -    PUMA_VERSION = VERSION = "7.1.0"
                -    CODE_NAME = "Neon Witch"
                +    PUMA_VERSION = VERSION = "7.2.0"
                +    CODE_NAME = "On The Corner"
        lib/puma/dsl.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/dsl.rb	2026-01-22 03:33:52.090391602 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/dsl.rb	2026-01-22 03:33:52.102391773 +0000
                @@ -218,0 +219,2 @@
                +    # @example
                +    #   activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true, data_only: true}
                @@ -242,0 +245 @@
                +      @options[:control_data_only] = opts[:data_only] if opts[:data_only]
                @@ -669,2 +672,2 @@
                -    # How many worker processes to run.  Typically this is set to
                -    # the number of available cores.
                +    # How many worker processes to run. Typically this is set to the number of
                +    # available cores.
                @@ -673 +676,6 @@
                -    # set, otherwise 0.
                +    # set, otherwise 0. Passing +:auto+ will set the value to
                +    # +Concurrent.available_processor_count+ (requires the concurrent-ruby gem).
                +    # On some platforms (e.g. under CPU quotas) this may be fractional, and Puma
                +    # will round down. If it rounds down to 0, Puma will run in single mode and
                +    # cluster-only hooks like +before_worker_boot+ will not execute.
                +    # If you rely on cluster-only hooks, set an explicit worker count.
                @@ -675 +683 @@
                -    # @note Cluster mode only.
                +    # A value of 0 or nil means run in single mode.
                @@ -678,0 +687 @@
                +    #   workers :auto
                @@ -683 +692 @@
                -      @options[:workers] = count.to_i
                +      @options[:workers] = count.nil? ? 0 : @config.send(:parse_workers, count)
                @@ -997,0 +1007 @@
                +    # @note When using `fork_worker`, this only applies to worker 0.
                @@ -1381 +1391 @@
                -    # @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
                +    # @see https://github.com/socketry/nio4r/blob/main/lib/nio/selector.rb
        lib/puma/launcher.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/launcher.rb	2026-01-22 03:33:52.090391602 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/launcher.rb	2026-01-22 03:33:52.102391773 +0000
                @@ -45 +45 @@
                -      ## Minimal initialization for a potential early restart (e.g. when pruning bundle)
                +      ## Minimal initialization before potential early restart (e.g. from bundle pruning)
                @@ -47,0 +48,2 @@
                +      # Advertise the CLI Configuration before config files are loaded
                +      Puma.cli_config = @config if defined?(Puma.cli_config)
                @@ -73,2 +75 @@
                -      # Advertise the Configuration
                -      Puma.cli_config = @config if defined?(Puma.cli_config)
                +      # Log after prune_bundler! to avoid duplicate logging if a restart occurs
        lib/puma/reactor.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/reactor.rb	2026-01-22 03:33:52.092391630 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/reactor.rb	2026-01-22 03:33:52.104391802 +0000
                @@ -78 +77,0 @@
                -      close_selector = true
                @@ -84 +82,0 @@
                -          monitor_wake_up = false
                @@ -86 +83,0 @@
                -            monitor_wake_up = true
                @@ -106,8 +103 @@
                -        # NoMethodError may be rarely raised when calling @selector.select, which
                -        # is odd.  Regardless, it may continue for thousands of calls if retried.
                -        # Also, when it raises, @selector.close also raises an error.
                -        if !monitor_wake_up && NoMethodError === e
                -          close_selector = false
                -        else
                -          retry
                -        end
                +        retry
                @@ -114,0 +105 @@
                +
                @@ -117 +108 @@
                -      @selector.close if close_selector
                +      @selector.close
        lib/puma/request.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/request.rb	2026-01-22 03:33:52.092391630 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/request.rb	2026-01-22 03:33:52.104391802 +0000
                @@ -39 +39 @@
                -    # It'll return +false+ when the connection is closed, this doesn't mean
                +    # It'll return +:close+ when the connection is closed, this doesn't mean
                @@ -41,0 +42,3 @@
                +    # It'll return +:keep_alive+ if the connection is a pipeline or keep-alive connection.
                +    # Which may contain additional requests.
                +    #
                @@ -48,2 +51 @@
                -    # @return [Boolean,:async]
                -    #
                +    # @return [:close, :keep_alive, :async]
                @@ -57 +59 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -170 +172 @@
                -    # @return [Boolean,:async] keep-alive status or `:async`
                +    # @return [:close, :keep_alive, :async]
                @@ -176 +178 @@
                -      return false if closed_socket?(socket)
                +      return :close if closed_socket?(socket)
                @@ -247 +249 @@
                -          return keep_alive
                +          return keep_alive ? :keep_alive : :close
                @@ -273 +275 @@
                -      !shutting_down? && keep_alive
                +      !shutting_down? && keep_alive ? :keep_alive : :close
        lib/puma/runner.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/runner.rb	2026-01-22 03:33:52.092391630 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/runner.rb	2026-01-22 03:33:52.104391802 +0000
                @@ -73 +73 @@
                -      app = Puma::App::Status.new @launcher, token
                +      app = Puma::App::Status.new @launcher, token: token, data_only: @options[:control_data_only]
        lib/puma/server.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/server.rb	2026-01-22 03:33:52.093391644 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/server.rb	2026-01-22 03:33:52.104391802 +0000
                @@ -302 +302 @@
                -    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/master/docs/architecture.md#connection-pipeline).
                +    # For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
                @@ -504 +504 @@
                -          when false
                +          when :close
                @@ -507 +507 @@
                -          when true
                +          when :keep_alive
        lib/puma/single.rb
                --- /tmp/d20260122-667-htboom/puma-7.1.0/lib/puma/single.rb	2026-01-22 03:33:52.093391644 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/lib/puma/single.rb	2026-01-22 03:33:52.104391802 +0000
                @@ -52,2 +52,2 @@
                -      @server = server = start_server
                -      server_thread = server.run
                +      @server = start_server
                +      server_thread = @server.run
        tools/Dockerfile
                --- /tmp/d20260122-667-htboom/puma-7.1.0/tools/Dockerfile	2026-01-22 03:33:52.093391644 +0000
                +++ /tmp/d20260122-667-htboom/puma-7.2.0/tools/Dockerfile	2026-01-22 03:33:52.105391816 +0000
                @@ -1,0 +2,2 @@
                +# Build (MRI): docker build -f tools/Dockerfile .
                +# Build (JRuby): docker build -f tools/Dockerfile --build-arg RUBY_IMAGE=jruby:9.4 .
                @@ -3 +5,2 @@
                -FROM ruby:3.2
                +ARG RUBY_IMAGE=ruby:latest
                +FROM ${RUBY_IMAGE}
                @@ -5 +8,2 @@
                -RUN apt-get update && apt-get install -y ragel
                +# Set BUNDLE_FROZEN=false if you need to update Gemfile.lock during a build.
                +ARG BUNDLE_FROZEN=true
                @@ -7,2 +11,6 @@
                -# throw errors if Gemfile has been modified since Gemfile.lock
                -RUN bundle config --global frozen 1
                +RUN apt-get update \
                +  && apt-get install -y --no-install-recommends ragel procps git \
                +  && rm -rf /var/lib/apt/lists/*
                +
                +# Only freeze Bundler and compile native extensions when using MRI.
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ] && [ "${BUNDLE_FROZEN}" = "true" ]; then bundle config --global frozen 1; fi
                @@ -15 +23 @@
                -RUN bundle exec rake compile
                +RUN if [ "$(ruby -e 'print RUBY_ENGINE')" = "ruby" ]; then bundle exec rake compile; fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies ruby Pull requests that update Ruby code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants