Skip to content

Commit 49728b5

Browse files
authored
feat(api): defer remote build creation for pending deployments (#2536)
Depot builds have short-lived tokens and their TTL is not exposed in the SDK. As queued deployments can stay in the queue for an arbitrary amount of time, deferring the remote build creation helps avoid expired Depot token issues.
1 parent d45696c commit 49728b5

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed

apps/webapp/app/routes/api.v1.deployments.$deploymentId.start.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ export async function action({ request, params }: ActionFunctionArgs) {
6161
return json({ error: "Deployment not found" }, { status: 404 });
6262
case "deployment_not_pending":
6363
return json({ error: "Deployment is not pending" }, { status: 409 });
64+
case "failed_to_create_remote_build":
65+
return json({ error: "Failed to create remote build" }, { status: 500 });
6466
case "other":
6567
default:
6668
error.type satisfies "other";

apps/webapp/app/v3/remoteImageBuilder.server.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { depot } from "@depot/sdk-node";
2-
import { Project } from "@trigger.dev/database";
2+
import { type ExternalBuildData } from "@trigger.dev/core/v3";
3+
import { type Project } from "@trigger.dev/database";
34
import { prisma } from "~/db.server";
45
import { env } from "~/env.server";
56

6-
export async function createRemoteImageBuild(project: Project) {
7+
export async function createRemoteImageBuild(
8+
project: Project
9+
): Promise<ExternalBuildData | undefined> {
710
if (!remoteBuildsEnabled()) {
811
return;
912
}

apps/webapp/app/v3/services/deployment.server.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { type AuthenticatedEnvironment } from "~/services/apiAuth.server";
22
import { BaseService } from "./baseService.server";
33
import { errAsync, fromPromise, okAsync } from "neverthrow";
44
import { type WorkerDeploymentStatus, type WorkerDeployment } from "@trigger.dev/database";
5-
import { logger, type GitMeta } from "@trigger.dev/core/v3";
5+
import { type ExternalBuildData, logger, type GitMeta } from "@trigger.dev/core/v3";
66
import { TimeoutDeploymentService } from "./timeoutDeployment.server";
77
import { env } from "~/env.server";
8+
import { createRemoteImageBuild } from "../remoteImageBuilder.server";
89

910
export class DeploymentService extends BaseService {
1011
public startDeployment(
@@ -46,11 +47,29 @@ export class DeploymentService extends BaseService {
4647
return okAsync(deployment);
4748
};
4849

49-
const updateDeployment = (deployment: Pick<WorkerDeployment, "id">) =>
50+
const createRemoteBuild = (deployment: Pick<WorkerDeployment, "id">) =>
51+
fromPromise(createRemoteImageBuild(authenticatedEnv.project), (error) => ({
52+
type: "failed_to_create_remote_build" as const,
53+
cause: error,
54+
})).map((build) => ({
55+
id: deployment.id,
56+
externalBuildData: build,
57+
}));
58+
59+
const updateDeployment = (
60+
deployment: Pick<WorkerDeployment, "id"> & {
61+
externalBuildData: ExternalBuildData | undefined;
62+
}
63+
) =>
5064
fromPromise(
5165
this._prisma.workerDeployment.updateMany({
5266
where: { id: deployment.id, status: "PENDING" }, // status could've changed in the meantime, we're not locking the row
53-
data: { ...updates, status: "BUILDING", startedAt: new Date() },
67+
data: {
68+
...updates,
69+
externalBuildData: deployment.externalBuildData,
70+
status: "BUILDING",
71+
startedAt: new Date(),
72+
},
5473
}),
5574
(error) => ({
5675
type: "other" as const,
@@ -75,11 +94,13 @@ export class DeploymentService extends BaseService {
7594
type: "failed_to_extend_deployment_timeout" as const,
7695
cause: error,
7796
})
78-
).map(() => undefined);
97+
);
7998

8099
return getDeployment()
81100
.andThen(validateDeployment)
101+
.andThen(createRemoteBuild)
82102
.andThen(updateDeployment)
83-
.andThen(extendTimeout);
103+
.andThen(extendTimeout)
104+
.map(() => undefined);
84105
}
85106
}

apps/webapp/app/v3/services/initializeDeployment.server.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,12 @@ export class InitializeDeploymentService extends BaseService {
8787
);
8888
}
8989

90-
// Try and create a depot build and get back the external build data
91-
const externalBuildData = await createRemoteImageBuild(environment.project);
90+
// For the `PENDING` initial status, defer the creation of the Depot build until the deployment is started.
91+
// This helps avoid Depot token expiration issues.
92+
const externalBuildData =
93+
payload.initialStatus === "PENDING"
94+
? undefined
95+
: await createRemoteImageBuild(environment.project);
9296

9397
const triggeredBy = payload.userId
9498
? await this._prisma.user.findFirst({

0 commit comments

Comments
 (0)