diff --git a/apps/webapp/app/routes/api.v1.deployments.$deploymentId.start.ts b/apps/webapp/app/routes/api.v1.deployments.$deploymentId.start.ts index da73cf1be3..1272a8418d 100644 --- a/apps/webapp/app/routes/api.v1.deployments.$deploymentId.start.ts +++ b/apps/webapp/app/routes/api.v1.deployments.$deploymentId.start.ts @@ -61,6 +61,8 @@ export async function action({ request, params }: ActionFunctionArgs) { return json({ error: "Deployment not found" }, { status: 404 }); case "deployment_not_pending": return json({ error: "Deployment is not pending" }, { status: 409 }); + case "failed_to_create_remote_build": + return json({ error: "Failed to create remote build" }, { status: 500 }); case "other": default: error.type satisfies "other"; diff --git a/apps/webapp/app/v3/remoteImageBuilder.server.ts b/apps/webapp/app/v3/remoteImageBuilder.server.ts index e1e6916c41..dca7fffb11 100644 --- a/apps/webapp/app/v3/remoteImageBuilder.server.ts +++ b/apps/webapp/app/v3/remoteImageBuilder.server.ts @@ -1,9 +1,12 @@ import { depot } from "@depot/sdk-node"; -import { Project } from "@trigger.dev/database"; +import { type ExternalBuildData } from "@trigger.dev/core/v3"; +import { type Project } from "@trigger.dev/database"; import { prisma } from "~/db.server"; import { env } from "~/env.server"; -export async function createRemoteImageBuild(project: Project) { +export async function createRemoteImageBuild( + project: Project +): Promise { if (!remoteBuildsEnabled()) { return; } diff --git a/apps/webapp/app/v3/services/deployment.server.ts b/apps/webapp/app/v3/services/deployment.server.ts index 9789cfc07e..495ea91496 100644 --- a/apps/webapp/app/v3/services/deployment.server.ts +++ b/apps/webapp/app/v3/services/deployment.server.ts @@ -2,9 +2,10 @@ import { type AuthenticatedEnvironment } from "~/services/apiAuth.server"; import { BaseService } from "./baseService.server"; import { errAsync, fromPromise, okAsync } from "neverthrow"; import { type WorkerDeploymentStatus, type WorkerDeployment } from "@trigger.dev/database"; -import { logger, type GitMeta } from "@trigger.dev/core/v3"; +import { type ExternalBuildData, logger, type GitMeta } from "@trigger.dev/core/v3"; import { TimeoutDeploymentService } from "./timeoutDeployment.server"; import { env } from "~/env.server"; +import { createRemoteImageBuild } from "../remoteImageBuilder.server"; export class DeploymentService extends BaseService { public startDeployment( @@ -46,11 +47,29 @@ export class DeploymentService extends BaseService { return okAsync(deployment); }; - const updateDeployment = (deployment: Pick) => + const createRemoteBuild = (deployment: Pick) => + fromPromise(createRemoteImageBuild(authenticatedEnv.project), (error) => ({ + type: "failed_to_create_remote_build" as const, + cause: error, + })).map((build) => ({ + id: deployment.id, + externalBuildData: build, + })); + + const updateDeployment = ( + deployment: Pick & { + externalBuildData: ExternalBuildData | undefined; + } + ) => fromPromise( this._prisma.workerDeployment.updateMany({ where: { id: deployment.id, status: "PENDING" }, // status could've changed in the meantime, we're not locking the row - data: { ...updates, status: "BUILDING", startedAt: new Date() }, + data: { + ...updates, + externalBuildData: deployment.externalBuildData, + status: "BUILDING", + startedAt: new Date(), + }, }), (error) => ({ type: "other" as const, @@ -75,11 +94,13 @@ export class DeploymentService extends BaseService { type: "failed_to_extend_deployment_timeout" as const, cause: error, }) - ).map(() => undefined); + ); return getDeployment() .andThen(validateDeployment) + .andThen(createRemoteBuild) .andThen(updateDeployment) - .andThen(extendTimeout); + .andThen(extendTimeout) + .map(() => undefined); } } diff --git a/apps/webapp/app/v3/services/initializeDeployment.server.ts b/apps/webapp/app/v3/services/initializeDeployment.server.ts index a355522772..0758dc231e 100644 --- a/apps/webapp/app/v3/services/initializeDeployment.server.ts +++ b/apps/webapp/app/v3/services/initializeDeployment.server.ts @@ -87,8 +87,12 @@ export class InitializeDeploymentService extends BaseService { ); } - // Try and create a depot build and get back the external build data - const externalBuildData = await createRemoteImageBuild(environment.project); + // For the `PENDING` initial status, defer the creation of the Depot build until the deployment is started. + // This helps avoid Depot token expiration issues. + const externalBuildData = + payload.initialStatus === "PENDING" + ? undefined + : await createRemoteImageBuild(environment.project); const triggeredBy = payload.userId ? await this._prisma.user.findFirst({