Commit 084271b8fd8 for php
commit 084271b8fd895b8cdfdcb9552bdd3575e94e65bf
Author: Jakub Zelenka <bukka@php.net>
Date: Thu Oct 29 10:20:09 2026 +0100
Fix flaky FPM test for bug #77023 (#24999)
The test sent two parallel requests to a pool with a single child and
expected the dynamic process manager to spawn a second child. That only
happens when the idle server maintenance heartbeat (1s) fires while the
child is busy, but the scripts kept it busy for just 300ms each, so the
spawn was a matter of luck and the total processes check failed on slow
machines.
Use a single request that blocks the child for longer than the heartbeat
so the spare child is always spawned, and rely on the fact that the
blocked child is the oldest idle one and is therefore quit first. One
blocked child is enough to verify the SIGKILL fallback. Replace the fixed
sleep with log timeouts and poll the status until the spare child is quit.
diff --git a/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt b/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt
index b20d5587503..56fbffc3f9c 100644
--- a/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt
+++ b/sapi/fpm/tests/bug77023-pm-dynamic-blocking-sigquit.phpt
@@ -2,7 +2,6 @@
FPM: Blocked SIGQUIT prevents idle process to be killed
--EXTENSIONS--
pcntl
---FLAKY--
--SKIPIF--
<?php
include "skipif.inc";
@@ -32,23 +31,30 @@
$code = <<<EOT
<?php
pcntl_sigprocmask(SIG_BLOCK, [SIGQUIT, SIGTERM]);
-usleep(300000);
+usleep(2000000);
EOT;
-
$tester = new FPM\Tester($cfg, $code);
$tester->start(extensions: ['pcntl']);
$tester->expectLogStartNotices();
-$tester->multiRequest(2);
+$tester->request()->expectEmptyBody();
$tester->status([
'total processes' => 2,
]);
-// wait for process to be killed
-sleep(7);
-$tester->expectLogWarning('child \\d+ exited on signal 9 \\(SIGKILL\\) after \\d+.\\d+ seconds from start', 'unconfined');
-$tester->expectLogNotice('child \\d+ started', 'unconfined');
-$tester->expectLogWarning('child \\d+ exited on signal 9 \\(SIGKILL\\) after \\d+.\\d+ seconds from start', 'unconfined');
+$tester->expectLogWarning(
+ 'child \\d+ exited on signal 9 \\(SIGKILL\\) after \\d+.\\d+ seconds from start',
+ 'unconfined',
+ timeoutSeconds: 10
+);
$tester->expectLogNotice('child \\d+ started', 'unconfined');
+// wait for the remaining spare process to be quit
+for ($i = 0; $i < 20; $i++) {
+ $status = json_decode($tester->request('json', [], '/status')->getBody('application/json'), true);
+ if (($status['total processes'] ?? null) === 1) {
+ break;
+ }
+ usleep(500000);
+}
$tester->status([
'total processes' => 1,
]);