feat(worker): add per-worker request_idle_timeout#2467
Conversation
Workers block in frankenphp_handle_request() with no way to wake up during quiet periods, so long-lived connections (database, Redis) can go stale, and warm in-memory state has no chance to refresh until the next request arrives. This adds an opt-in, per-worker idle timeout. When it's configured, after that long without a request frankenphp_handle_request() returns the new FRANKENPHP_REQUEST_IDLE_TIMEOUT constant (-1) instead of blocking. No request is handled, so the worker can reconnect or refresh settings and feature flags and then keep looping, without restarting the script and losing its warm state. The return type widens from bool to int|bool. -1 is only ever emitted when the timeout is set, so existing scripts that check true/false are unaffected, and the feature is off by default. - Caddyfile: request_idle_timeout <duration> inside a worker block; 0 (the default) disables it, negative values are rejected - on an idle tick the request superglobals are emptied ($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER, $_REQUEST) and $_SESSION is dropped, while $_ENV and $GLOBALS are left untouched - idle ticks don't count toward max_requests - adds the FRANKENPHP_REQUEST_IDLE_TIMEOUT constant, docs, and tests
|
Project that I am working on uses heavy edge caching, and it is timezone sensitive. It can be minutes between backend post requests and I saw in the logs issues with DB connection going stale. I thought having this idle timeout could solve this issue. |
|
Is there ever a scenario where you might want to have a hard limit on how long a worker can run instead of how long it can wait for a request? Then you could just restart the worker with a background goroutine (for example by just calling |
A background goroutine calling thread.reboot() after X seconds races with the request lifecycle. reboot() only succeeds when the thread is in Ready state (the CAS returns false otherwise), so if it fires mid-request it silently no-ops as far as I understand. |
|
Oh, I get it now, you are basically pinging worker /path/to/worker.php {
ping idle 10s "/refresh" # send a request on path /refresh or directly return "/refresh" from frankenphp_handle_request()
}
# or
worker /path/to/worker.php {
ping 10s "/refresh" # there are probably many other use cases for just pinging repeatedly
} |
Workers block in frankenphp_handle_request() with no way to wake up during quiet periods, so long-lived connections (database, Redis) can go stale, and warm in-memory state has no chance to refresh until the next request arrives.
This adds an opt-in, per-worker idle timeout. When it's configured, after that long without a request frankenphp_handle_request() returns the new FRANKENPHP_REQUEST_IDLE_TIMEOUT constant (-1) instead of blocking. No request is handled, so the worker can reconnect or refresh settings and feature flags and then keep looping, without restarting the script and losing its warm state.
The return type widens from bool to int|bool. -1 is only ever emitted when the timeout is set, so existing scripts that check true/false are unaffected, and the feature is off by default.