mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-09-19 17:50:20 +00:00
aio-interface: fix nginx reverse proxy read timeout blocks AIO from starting consecutive containers (#8016)
* Fix: prevent nginx proxy read timeout from blocking AIO container startup When AIO runs behind an nginx reverse proxy and a user clicks Start, image pulls produce no streaming output for minutes at a time. nginx's proxy_read_timeout fires, drops the upstream connection, and PHP then aborts on the next write attempt (ignore_user_abort defaults to false), leaving all containers after the first one never started. Two fixes: 1. startStreamingResponse(): add ignore_user_abort(true) so PHP never terminates if the connection is already gone. 2. PullImage(): stream the Docker NDJSON pull response and write a "Pulling image" heartbeat at most once every 5 s, keeping the nginx connection alive. Also surfaces Docker-level stream errors that the old buffered call silently ignored, guards against malformed newline-free responses with a 1 MB buffer limit, and unifies the duplicate catch-block retry logic. Agent-Logs-Url: https://github.com/nextcloud/all-in-one/sessions/4fd13605-63fb-4693-8a95-89ccec31f7d3 Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com> * As heartbeat send a dot regularly Rather than repeating the message, send a "magic" dot, which gets appended to the previous line. Previously the heartbeats weren't sent regulary because reading the data into a buffer caused a lag. Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> * Remove left-over constants Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> * Reduce timeout to stay within nginx's default timeout of 5s Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> * Fix duplicated library namespace inclusion Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> * Deal with preg_replace possibly returning null Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> * update the version tag Signed-off-by: Simon L. <szaimen@e.mail.de> --------- Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> Signed-off-by: Simon L. <szaimen@e.mail.de> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com> Co-authored-by: Pablo Zmdl <pablo@nextcloud.com> Co-authored-by: Simon L. <szaimen@e.mail.de>
This commit is contained in:
co-authored by
szaimen
Pablo Zmdl
Simon L.
parent
d20eb5edda
commit
fc4bb548a4
@@ -420,7 +420,7 @@ readonly class DockerController {
|
||||
<head>
|
||||
<link rel="stylesheet" href="../../style.css?v12" media="all" />
|
||||
<script type="text/javascript" src="../../apply-theme.js?v1"></script>
|
||||
<script type="text/javascript" src="../../scroll-into-view.js"></script>
|
||||
<script type="text/javascript" src="../../scroll-into-view.js?v1"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -428,6 +428,11 @@ readonly class DockerController {
|
||||
}
|
||||
|
||||
private function startStreamingResponse(Response $response) : Response {
|
||||
// Ensure the script keeps running even if the client connection drops (e.g. due to a
|
||||
// reverse proxy read timeout during a long image pull). Without this, PHP would abort
|
||||
// on the first write after the connection is gone, leaving only some containers started.
|
||||
ignore_user_abort(true);
|
||||
|
||||
$nonbufResp = $response
|
||||
->withBody(new NonBufferedBody())
|
||||
->withHeader('Content-Type', 'text/html; charset=utf-8')
|
||||
@@ -448,12 +453,19 @@ readonly class DockerController {
|
||||
// if it'll actually pull an image), but which should not need to know anything about the
|
||||
// wanted markup or formatting.
|
||||
$addToStreamingResponseBody = function (string $message, ?Container $container = null) use ($nonbufResp) : void {
|
||||
// Strip ANSI codes.
|
||||
$message = preg_replace('/\e[[][A-Za-z0-9];?[0-9]*m?/', '', $message);
|
||||
if ($container) {
|
||||
$message = "{$container->displayName}: {$message}";
|
||||
// If the message is a single dot we treat it as a progress indicator and send a specific, empty
|
||||
// HTML element, which gets special treatment by the Javascript code.
|
||||
if ($message === '.') {
|
||||
$html = "<span class='progress-indicator'></span>";
|
||||
} else {
|
||||
// Strip ANSI codes. If the operation fails, use the unchanged $message as fallback.
|
||||
$text = preg_replace('/\e[[][A-Za-z0-9];?[0-9]*m?/', '', $message) ?? $message;
|
||||
if ($container) {
|
||||
$text = sprintf("%s: %s", $container->displayName, $text);
|
||||
}
|
||||
$html = sprintf("<div>%s</div>", htmlspecialchars($text, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'));
|
||||
}
|
||||
$nonbufResp->getBody()->write("<div>" . htmlspecialchars("{$message}", ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . "</div>");
|
||||
$nonbufResp->getBody()->write($html);
|
||||
};
|
||||
|
||||
return $addToStreamingResponseBody;
|
||||
|
||||
Reference in New Issue
Block a user