Skip to content

Commit 79da4f8

Browse files
committed
fix(webapp,core): retry run resume through transient database outages
Resuming a run after a wait calls the engine's continue endpoint. When the database was briefly unreachable, that route caught the Prisma infrastructure error and returned a non-retryable 422, so the worker aborted the run with TASK_EXECUTION_ABORTED over a transient blip. The continue route now lets infrastructure errors propagate to the generic 500 handler (scrubbed and retryable), matching how the trigger path already treats them. The worker's continue call also retries with a longer, jittered backoff so it can ride out an outage lasting tens of seconds without stampeding the database on recovery. Genuine validation errors still return 422.
1 parent fd4f02b commit 79da4f8

3 files changed

Lines changed: 35 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/core": patch
3+
---
4+
5+
Runs resuming after a wait now survive a transient platform database outage instead of failing with `TASK_EXECUTION_ABORTED`. The worker retries the resume call generously with jittered backoff, so a brief blip while the run is being continued no longer aborts it.

apps/webapp/app/routes/engine.v1.worker-actions.runs.$runFriendlyId.snapshots.$snapshotFriendlyId.continue.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { WorkerApiContinueRunExecutionRequestBody } from "@trigger.dev/core
44
import { z } from "zod";
55
import { logger } from "~/services/logger.server";
66
import { createLoaderWorkerApiRoute } from "~/services/routeBuilders/apiBuilder.server";
7-
import { clientSafeErrorMessage } from "~/utils/prismaErrors";
7+
import { clientSafeErrorMessage, isInfrastructureError } from "~/utils/prismaErrors";
88

99
export const loader = createLoaderWorkerApiRoute(
1010
{
@@ -31,7 +31,21 @@ export const loader = createLoaderWorkerApiRoute(
3131

3232
return json(continuationResult);
3333
} catch (error) {
34-
logger.warn("Failed to suspend run", { runFriendlyId, snapshotFriendlyId, error });
34+
logger.warn("Failed to continue run execution", {
35+
runFriendlyId,
36+
snapshotFriendlyId,
37+
error,
38+
});
39+
40+
// A Prisma infrastructure error (e.g. P1001 "Can't reach database
41+
// server") means the DB was transiently unreachable while resuming. A 422
42+
// is non-retryable, so the worker would permanently abort a run over a
43+
// blip. Let it propagate to the generic 500 handler, which scrubs the
44+
// message and is retried by the worker's HTTP client.
45+
if (isInfrastructureError(error)) {
46+
throw error;
47+
}
48+
3549
if (error instanceof Error) {
3650
throw json({ error: clientSafeErrorMessage(error) }, { status: 422 });
3751
}

packages/core/src/v3/runEngineWorker/workload/http.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,20 @@ export class WorkloadHttpClient {
132132
headers: {
133133
...this.defaultHeaders(),
134134
},
135+
},
136+
{
137+
// Resuming after a wait is idempotent (guarded server-side by the
138+
// snapshot id), so retry generously to ride out a transient database
139+
// outage rather than aborting the run. `randomize` jitters the delay
140+
// so a fleet of runs resuming at once doesn't stampede the DB the
141+
// moment it recovers.
142+
retry: {
143+
minTimeoutInMs: 500,
144+
maxTimeoutInMs: 10_000,
145+
maxAttempts: 8,
146+
factor: 2,
147+
randomize: true,
148+
},
135149
}
136150
)
137151
);

0 commit comments

Comments
 (0)