From 3ff3dcf62948298e8200155d8e6561fd55ae3e70 Mon Sep 17 00:00:00 2001 From: Adhik Joshi Date: Fri, 21 Aug 2026 12:37:22 +0530 Subject: [PATCH] Sweep visibility: log and cancel over-budget requests whose client left The timeout sweep skipped silently when the request's fd was already closed - exactly what happens when a downstream proxy (nginx at 210s) gives up before octane's budget: the worker kept burning to completion and nothing was ever logged, making a whole class of production stalls invisible. Both over-budget cases now log (with age, worker pid, fd), and the client-gone case cancels the coroutine instead of letting it run out the clock. E2E: alive-fd hang -> 408 + log; abandoned hang -> '(client gone)' log + cancel. --- .../EnsureRequestsDontExceedMaxExecutionTime.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Swoole/Actions/EnsureRequestsDontExceedMaxExecutionTime.php b/src/Swoole/Actions/EnsureRequestsDontExceedMaxExecutionTime.php index 7986188..f084876 100644 --- a/src/Swoole/Actions/EnsureRequestsDontExceedMaxExecutionTime.php +++ b/src/Swoole/Actions/EnsureRequestsDontExceedMaxExecutionTime.php @@ -50,13 +50,22 @@ public function __invoke() // Delete the timer entry first $this->timerTable->del($coroutineId); - // Check if the connection still exists + $age = time() - $row['time']; + + // Check if the connection still exists. Log this case too: a + // dead fd here means a downstream proxy already gave up on a + // request the worker is STILL burning - silence made a whole + // class of production stalls invisible (the 210s nginx 504s). if ($this->server instanceof Server && ! $this->server->exists($row['fd'])) { + error_log("⏱️ Request timeout (client gone): Coroutine #{$coroutineId} ran {$age}s of {$this->maxExecutionTime}s budget on worker {$row['worker_pid']}; fd {$row['fd']} already closed"); + + $this->cancelCoroutine($coroutineId); + continue; } // Log the timeout - error_log("⏱️ Request timeout: Coroutine #{$coroutineId} exceeded {$this->maxExecutionTime}s max execution time"); + error_log("⏱️ Request timeout: Coroutine #{$coroutineId} ran {$age}s, exceeded {$this->maxExecutionTime}s max execution time (worker {$row['worker_pid']}, fd {$row['fd']})"); $cancelled = $this->cancelCoroutine($coroutineId);