Skip to content

fix: keep PHP running until Caddy finishes graceful shutdown - #2645

Draft
nesl247 wants to merge 1 commit into
php:mainfrom
nesl247:fix/graceful-php-shutdown
Draft

fix: keep PHP running until Caddy finishes graceful shutdown#2645
nesl247 wants to merge 1 commit into
php:mainfrom
nesl247:fix/graceful-php-shutdown

Conversation

@nesl247

@nesl247 nesl247 commented Sep 11, 2026

Copy link
Copy Markdown

Fixes #2644.

Caddy stops its apps without dependency ordering. Calling frankenphp.Shutdown() from FrankenPHPApp.Stop() can therefore stop PHP while the HTTP app is still accepting requests during shutdown_delay, producing HTTP 500 responses.

Register a single process-global caddy.OnExit callback so PHP stays available until all Caddy apps have stopped, including the HTTP shutdown delay and in-flight request draining. Keep the existing reload shutdown path unchanged.

Add a process-level regression to the existing Linux test workflow, using the CLI it already builds. Five fresh processes exercise the unordered stop path. The test verifies PHP responses during the shutdown delay, an in-flight response spanning listener closure, actual PHP teardown, and clean process exit. A bounded release handshake avoids waiting for a fixed long-running request.

Validated against current main (daead870980d2aba0c2df76cbea880b5a608ff0b) on Linux ARM64 with PHP 8.5.9 and Go 1.27.1:

  • The regression passes with this change and fails on unpatched main after SIGTERM.
  • The existing reload_test.sh integration check passes.
  • Go formatting, Bash syntax, ShellCheck, and actionlint pass.

The full PHP-version matrix and worker-mode shutdown were not run locally. The regression is wired into the existing PHP 8.2–8.5 Linux jobs. Feedback on the process-exit lifecycle hook is welcome.

Caddy stops apps without dependency ordering. Shutting down PHP from the
FrankenPHP app Stop method can break requests while HTTP remains open.
Register one global OnExit callback after all apps have drained instead,
while preserving the existing reload shutdown path.

Add a process-level regression for service during shutdown_delay,
in-flight request draining, PHP teardown, and successful process exit.
Run it in the existing Linux PHP matrix using the already-built CLI.

Validation on current main with Linux ARM64, PHP 8.5.9 and Go 1.27.1:
patched regression and existing reload integration pass; unpatched main
fails the regression. Go formatting, Bash syntax, ShellCheck and actionlint
pass. Full PHP-version matrix and worker-mode shutdown not run locally.
@AlliBalliBaba

Copy link
Copy Markdown
Contributor

Makes sense 👍 . Could you maybe also test that a worker script is still able to do graceful shutdown, eg:

#  worker.php
while(frankenphp_handle_request($handler)){
}

# Make sure this code here still runs in a test, for example by creating a temp file
shutdownlogic();

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PHP requests return 500 during shutdown_delay after SIGTERM

2 participants