-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathfindOrCreateBackgroundWorker.server.ts
More file actions
81 lines (77 loc) · 3.16 KB
/
Copy pathfindOrCreateBackgroundWorker.server.ts
File metadata and controls
81 lines (77 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import type { CreateBackgroundWorkerRequestBody } from "@trigger.dev/core/v3";
import { BackgroundWorkerId } from "@trigger.dev/core/v3/isomorphic";
import {
isUniqueConstraintError,
type BackgroundWorker,
type PrismaClientOrTransaction,
type WorkerDeployment,
} from "@trigger.dev/database";
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
import { ServiceValidationError } from "../common.server";
import { stripBackgroundWorkerMetadataForStorage } from "../stripBackgroundWorkerMetadataForStorage.server";
/**
* Idempotent on `(project, environment, version)` for sequential calls, not concurrent calls.
*
* Failure shapes the caller distinguishes:
* - `ServiceValidationError` (409): definitive — contentHash drift means a different build
* is being pushed under the same deployment version, so the caller should fail the
* deployment instead of waiting for a timeout.
* - Plain `Error`: transient — two attempts raced the `create()` call and the loser caught
* the unique-index violation. The caller should propagate this as 5xx so the CLI's
* retry/backoff hits findFirst on the next attempt and returns the winner's row.
*/
export async function findOrCreateBackgroundWorker(
environment: AuthenticatedEnvironment,
deployment: WorkerDeployment,
body: CreateBackgroundWorkerRequestBody,
prisma: PrismaClientOrTransaction
): Promise<BackgroundWorker> {
const existing = await prisma.backgroundWorker.findFirst({
where: {
projectId: environment.projectId,
runtimeEnvironmentId: environment.id,
version: deployment.version,
},
});
if (existing && existing.contentHash === body.metadata.contentHash) {
return existing;
}
if (existing) {
throw new ServiceValidationError(
"A background worker for this deployment version already exists with a different content hash",
409
);
}
try {
return await prisma.backgroundWorker.create({
data: {
...BackgroundWorkerId.generate(),
version: deployment.version,
runtimeEnvironmentId: environment.id,
projectId: environment.projectId,
metadata: stripBackgroundWorkerMetadataForStorage(body.metadata),
contentHash: body.metadata.contentHash,
cliVersion: body.metadata.cliPackageVersion,
sdkVersion: body.metadata.packageVersion,
supportsLazyAttempts: body.supportsLazyAttempts,
engine: body.engine,
runtime: body.metadata.runtime,
runtimeVersion: body.metadata.runtimeVersion,
},
});
} catch (error) {
// Concurrent attempts raced past `findFirst` and both reached `create`. Surface
// a clear, non-Prisma error so the 5xx the caller returns isn't an opaque
// P2002 — the CLI's retry will then hit `findFirst` and find the winner's row.
// Intentionally NOT a ServiceValidationError so the caller doesn't fail-deploy
// on a transient race.
if (
isUniqueConstraintError(error, ["projectId", "runtimeEnvironmentId", "version"])
) {
throw new Error(
"Concurrent background worker registration detected for this deployment version; please retry"
);
}
throw error;
}
}