From aaec9e878a28f96c9ab033f9ff402e94a20016f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Almeida?= Date: Mon, 11 May 2026 23:53:41 +0100 Subject: [PATCH] fix(lifecycle): make agentctl health retry delay cancelable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace `time.Sleep(retryDelay)` in `waitForHealth` (container.go) and `waitForAgentctlHealthWith` (executor_docker.go) with a cancelable `select { <-ctx.Done() | <-time.After(retryDelay) }`. Also skip the final retry's sleep — the loop only re-enters when `i+1 < maxRetries`, so the extra delay was just added latency on aborted launches. Cancellation now propagates within ≤500 ms instead of waiting for the next probe iteration to observe `ctx.Err()`. --- apps/backend/internal/agent/lifecycle/container.go | 11 ++++++++++- .../internal/agent/lifecycle/executor_docker.go | 8 +++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/backend/internal/agent/lifecycle/container.go b/apps/backend/internal/agent/lifecycle/container.go index 8f5d436a28..d162a1f740 100644 --- a/apps/backend/internal/agent/lifecycle/container.go +++ b/apps/backend/internal/agent/lifecycle/container.go @@ -270,7 +270,16 @@ func (cm *ContainerManager) waitForHealth(ctx context.Context, ctl *agentctl.Con if ctx.Err() != nil { return ctx.Err() } - time.Sleep(retryDelay) + // Cancelable wait that also skips the final retry's sleep — the loop + // only re-enters if i+1 < maxRetries, so the extra delay was just + // added latency on aborted launches. + if i+1 < maxRetries { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(retryDelay): + } + } } if lastErr != nil { diff --git a/apps/backend/internal/agent/lifecycle/executor_docker.go b/apps/backend/internal/agent/lifecycle/executor_docker.go index 379f72caaa..c15657d159 100644 --- a/apps/backend/internal/agent/lifecycle/executor_docker.go +++ b/apps/backend/internal/agent/lifecycle/executor_docker.go @@ -495,7 +495,13 @@ func waitForAgentctlHealthWith(ctx context.Context, ctl healthChecker, maxRetrie if ctx.Err() != nil { return ctx.Err() } - time.Sleep(retryDelay) + if i+1 < maxRetries { + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(retryDelay): + } + } } if lastErr != nil {