BUG: API deploy handler uses request context — deployment cancelled on client disconnect #105

Closed
opened 2026-02-20 12:28:13 +01:00 by clawbot · 0 comments
Collaborator

Severity: HIGH

File & Line

internal/handlers/api.go:345

Description

HandleAPITriggerDeploy calls h.deploy.Deploy(request.Context(), ...) directly with the HTTP request context. When the API client disconnects (or times out), request.Context() is cancelled, which propagates into the deploy service and cancels the build/deploy mid-operation.

The HTML handler (HandleAppDeploy in app.go:355) correctly uses context.WithoutCancel(request.Context()) and runs the deployment in a goroutine.

// api.go:345 — BUG: uses request context directly
deployErr := h.deploy.Deploy(request.Context(), application, nil, true)

// app.go:355 — CORRECT: detached context in goroutine
deployCtx := context.WithoutCancel(request.Context())
go func(ctx context.Context, appToDeploy *models.App) {
    deployErr := h.deploy.Deploy(ctx, appToDeploy, nil, false)
    ...
}(deployCtx, application)

Impact

Any API-triggered deployment will be cancelled if the HTTP client disconnects before the build finishes (which can take 30+ minutes). The deployment will be left in a partially-built state. This makes the API deploy endpoint essentially unreliable.

Suggested Fix

Use context.WithoutCancel and run in a goroutine, same as the HTML handler. Return 202 Accepted immediately (which it already does, but after the deploy starts synchronously).

## Severity: HIGH ## File & Line `internal/handlers/api.go:345` ## Description `HandleAPITriggerDeploy` calls `h.deploy.Deploy(request.Context(), ...)` directly with the HTTP request context. When the API client disconnects (or times out), `request.Context()` is cancelled, which propagates into the deploy service and cancels the build/deploy mid-operation. The HTML handler (`HandleAppDeploy` in `app.go:355`) correctly uses `context.WithoutCancel(request.Context())` and runs the deployment in a goroutine. ```go // api.go:345 — BUG: uses request context directly deployErr := h.deploy.Deploy(request.Context(), application, nil, true) // app.go:355 — CORRECT: detached context in goroutine deployCtx := context.WithoutCancel(request.Context()) go func(ctx context.Context, appToDeploy *models.App) { deployErr := h.deploy.Deploy(ctx, appToDeploy, nil, false) ... }(deployCtx, application) ``` ## Impact Any API-triggered deployment will be cancelled if the HTTP client disconnects before the build finishes (which can take 30+ minutes). The deployment will be left in a partially-built state. This makes the API deploy endpoint essentially unreliable. ## Suggested Fix Use `context.WithoutCancel` and run in a goroutine, same as the HTML handler. Return 202 Accepted immediately (which it already does, but after the deploy starts synchronously).
clawbot added this to the 1.0 milestone 2026-02-20 12:28:13 +01:00
clawbot added the
bug
label 2026-02-20 12:28:13 +01:00
clawbot self-assigned this 2026-02-20 12:28:13 +01:00
sneak closed this issue 2026-02-20 13:47:14 +01:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sneak/upaas#105
No description provided.