v1.13.0: config reload returns HTTP 500 "server is not registered, you must first call frankenphp.Init() with the WithServer() option" while workers boot (regression from v1.12.7)
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
- #2705 của @dunglas — đã đóng, không merge
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 54/100
Hướng nghiên cứu
Start with server.go around ServeHTTP and caddy/module.go around lines 229–232, where the issue traces ErrNotRunning into HTTP 500 responses. Compare the reload lifecycle with the linked discussions in #2648, #2645, and #2469. Reproduce using the provided worker script and Caddyfile with BOOT_DELAY_MS=300, then verify repeated config reloads no longer cause 500 responses.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
What happened?
Since v1.13.0, every config reload in worker mode makes FrankenPHP answer requests with an HTTP 500 and an empty body for as long as the new workers take to boot. The error log shows server is not registered, you must first call frankenphp.Init() with the WithServer() option (ErrNotRunning), raised at caddy.(*FrankenPHPModule).ServeHTTP (module.go:231). On v1.12.7, the same setup and load produce no 500s.
We found this with Laravel Octane: php artisan octane:reload does a GET /config/apps/frankenphp on the admin API and PATCHes the same body back with Cache-Control: must-revalidate. The bug also reproduces without Laravel and Octane, using a minimal worker script with a simulated bootstrap delay (see below).
Minimal reproduction
public/worker.php:
<?php
// BOOT_DELAY_MS simulates a framework bootstrap (Laravel takes ~300 ms here).
usleep((int) (getenv('BOOT_DELAY_MS') ?: 0) * 1000);
ignore_user_abort(true);
$handler = static function (): void {
echo 'ok';
};
while (frankenphp_handle_request($handler)) {
gc_collect_cycles();
}
Caddyfile:
{
admin 127.0.0.1:{$ADMIN_PORT}
auto_https disable_redirects
frankenphp {
worker {
file /path/to/public/worker.php
num 2
}
}
}
http://:{$PORT} {
bind 127.0.0.1
route {
root * /path/to/public
php_server {
index worker.php
try_files {path} worker.php
}
}
}
reload.sh (what Laravel Octane's octane:reload sends):
#!/bin/sh
ADMIN=${ADMIN:-http://127.0.0.1:8097}
curl -s "$ADMIN/config/apps/frankenphp" -o /tmp/fp-cfg.json
curl -s -X PATCH -H 'Content-Type: application/json' -H 'Cache-Control: must-revalidate' \
--data-binary @/tmp/fp-cfg.json "$ADMIN/config/apps/frankenphp"
Steps:
PORT=3097 ADMIN_PORT=8097 BOOT_DELAY_MS=300 frankenphp run --config Caddyfile- Generate about 20 req/s against
http://127.0.0.1:3097/(we used batches of 4 parallelcurl -m 10every 200 ms). - Run
reload.sha few times, 10 s apart. - Count the non-200 responses.
Results (3 reloads per round, ~800–900 requests per round; v1.12.7 and v1.13.0 side by side on the same host):
| Setup | v1.12.7 | v1.13.0 |
|---|---|---|
Minimal worker, BOOT_DELAY_MS=0 (2 rounds) |
0 / 0 errors | 0 / 0 errors |
Minimal worker, BOOT_DELAY_MS=300 (2 rounds) |
0 / 0 errors | 15 / 20 × HTTP 500 |
Laravel 12.61.1 + Octane 2.17.4, 2 workers, octane:reload (4 rounds over the day) |
0 / 0 / 0 / 0 × HTTP 500 | 21 / 22 / 17 / 14 × HTTP 500 |
- With a 0 ms boot the window is only ~28 ms, so you rarely hit it. It grows with worker boot time, which is why real applications hit it on every reload.
- The 500s start 0.05–0.5 s after the PATCH, and each one returns in under 1 ms (
duration≈ 0.0001 s) withContent-Length: 0and only theServer: FrankenPHP Caddyheader. So the request is rejected immediately, not queued. - We saw 2 to 8 failed requests per reload at 20 req/s. That is every request arriving in that window.
Timeline of one reload (Laravel Octane setup, v1.13.0, debug log; timestamps are seconds after 1791409991):
.220 admin.api received request GET /config/apps/frankenphp
.226 admin.api received request PATCH /config/apps/frankenphp (Cache-Control: must-revalidate)
.227 admin admin endpoint started
.254 frankenphp PHP init of the new config begins (first PHP warning logged)
.327 http.log.error 500 "server is not registered ..." x4
.527 http.log.error 500 "server is not registered ..." x4
.553 frankenphp FrankenPHP started 🐘 {"php_version":"8.4.26","total_threads":32,"worker_threads":2,"max_threads":32,"max_requests":0}
.553 frankenphp FrankenPHP stopped 🐘
.553 http servers shutting down with eternal grace period
.747 first HTTP 200 again
.772 admin stopped previous server
From the source, Server.ServeHTTP returns ErrNotRunning when isRegistered is false (server.go, around line 152), and FrankenPHPModule.ServeHTTP turns every non-ErrRejected error into a 500 (caddy/module.go:229-232). It looks like during a reload the old HTTP server keeps accepting requests while the FrankenPHP server it points at has already been unregistered and the new one is not registered yet. On v1.12.7 those requests were served (or waited) instead of failing.
This may be related to #2648 ("hand off PHP requests during configuration reloads", which mentions 503s), #2645 (the same class of problem on the SIGTERM shutdown path, which explicitly leaves the reload path unchanged) and #2469. As far as we can tell, the 500 ErrNotRunning variant on reload is not tracked yet.
A smaller side note: with the Laravel setup, both versions also occasionally leave a request hanging (no response within 10 s) during a reload: 1 in ~1,800 requests on v1.12.7 and 7 in ~1,800 on v1.13.0. The minimal reproduction did not show this, so we are not sure it is the same issue.
Build Type
deb packages
Worker Mode
Yes
Operating System
GNU/Linux
CPU Architecture
x86_64
PHP configuration
phpinfo() output
FrankenPHP v1.13.0 PHP 8.4 Caddy v2.11.7 h1:yj0Y4fYZGPkSvibBJ1sTWE33xC0fxztVyXEW5iIdUT4= (go1.27.1)
deb: frankenphp 1.13.0+php84-1, php-zts-embed 8.4.26-2, php-zts-cli 8.4.26-2 (pkg.henderkes.com, "Static-PHP:php-zts")
Compared with:
FrankenPHP v1.12.7 PHP 8.4 Caddy v2.11.4 h1:XKxkMTgNSizEvKG6QHue6cAsFOteU2qA61w2tKkCWi0=
deb: frankenphp 1.12.7+php84-1, php-zts-embed 8.4.25-1
PHP 8.4.26, ZTS=1, ini: /etc/php-zts/php.ini (+ scan dir)
Extensions: Core date libxml openssl pcre zlib calendar ctype curl dom json fileinfo filter hash iconv SPL
mbstring pcntl session standard bz2 posix random readline Reflection exif SimpleXML sockets sodium tokenizer
xml xmlreader xmlwriter apcu bcmath brotli Phar ftp gd gettext gmp imagick intl ldap lz4 msgpack mysqlnd PDO
pgsql soap ssh2 tidy xsl yaml zip zstd igbinary memcached mysqli pdo_mysql pdo_pgsql redis Zend OPcache
(extension packages are still at 8.4.25 in the repository; the minimal worker uses none of them)
OS: Debian 12.15 (bookworm), kernel 6.1.0-53-amd64, 16 vCPU
Laravel setup: Laravel Framework 12.61.1, laravel/octane v2.17.4,
`php artisan octane:start --server=frankenphp --workers=2 --max-requests=500`
Relevant log output
Relevant log output
{"level":"error","ts":1791410386.07222,"logger":"http.log.error","msg":"server is not registered, you must first call frankenphp.Init() with the WithServer() option","request":{"remote_ip":"127.0.0.1","remote_port":"45880","client_ip":"127.0.0.1","proto":"HTTP/1.1","method":"GET","host":"127.0.0.1:3097","uri":"/","headers":{"User-Agent":["curl/7.88.1"],"Accept":["*/*"]}},"duration":0.000226745,"status":500,"err_id":"pp5za8t9u","err_trace":"caddy.(*FrankenPHPModule).ServeHTTP (module.go:231)"}
# HTTP response for such a request:
HTTP/1.1 500 Internal Server Error
Server: FrankenPHP Caddy
Content-Length: 0
- Ngôn ngữ chính
- Go
- Star
- 11.4k
- Fork
- 494
- Merge trung bình
- 2 ngày 18 giờ
- Pull request đã merge (30 ngày)
- 32
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của php/frankenphp
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
php/frankenphp#2671 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Include frankenphp version in logsCó thể đã có người làm @ousamabenyounes đã nhận 87 ngày trước. Đang mởenhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
php/frankenphp#2483 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
suggestion about compile.mdCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mởenhancement
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 68/100
php/frankenphp#601 · 5 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 15/100
php/frankenphp#2715 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 8/100
php/frankenphp#2714 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của php/frankenphp
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 81/100
apache/rocketmq-dashboard#6895 ·
Maintainer thường phản hồi trong vòng 3 ngày
-
agent-butler-finding chore
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
jordansmall/spindrift#5466 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 87/100
777genius/agent-notifications#490 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
devantler-tech/ksail#7836 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
keyxmakerx/Chronicle#1469 ·
Maintainer thường phản hồi trong vòng 1 ngày