Skip to content

Commit 4cbbadb

Browse files
committed
refactor: consolidate template creation logic into ComputeTemplateCreationService.handleDeployTemplate
1 parent 5d24dd1 commit 4cbbadb

File tree

3 files changed

+102
-161
lines changed

3 files changed

+102
-161
lines changed

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { env } from "~/env.server";
33
import { logger } from "~/services/logger.server";
44
import type { PrismaClientOrTransaction } from "~/db.server";
55
import { FEATURE_FLAG, makeFlag } from "~/v3/featureFlags.server";
6+
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
7+
import { ServiceValidationError } from "./baseService.server";
8+
import { FailDeploymentService } from "./failDeployment.server";
69

710
type TemplateCreationMode = "required" | "shadow" | "skip";
811

@@ -19,6 +22,80 @@ export class ComputeTemplateCreationService {
1922
}
2023
}
2124

25+
/**
26+
* Handle template creation for a deployment. Call this before setting DEPLOYED.
27+
*
28+
* - Required mode: creates template synchronously, fails deployment on error
29+
* - Shadow mode: fires background template creation (returns immediately)
30+
* - Skip: no-op
31+
*
32+
* Throws ServiceValidationError if required mode fails (caller should stop finalize).
33+
*/
34+
async handleDeployTemplate(options: {
35+
projectId: string;
36+
imageReference: string;
37+
deploymentFriendlyId: string;
38+
authenticatedEnv: AuthenticatedEnvironment;
39+
prisma: PrismaClientOrTransaction;
40+
writer?: WritableStreamDefaultWriter;
41+
}): Promise<void> {
42+
const mode = await this.resolveMode(options.projectId, options.prisma);
43+
44+
if (mode === "skip") {
45+
return;
46+
}
47+
48+
if (mode === "shadow") {
49+
this.createTemplate(options.imageReference, { background: true }).catch((error) => {
50+
logger.error("Shadow compute template creation failed", {
51+
id: options.deploymentFriendlyId,
52+
imageReference: options.imageReference,
53+
error: error instanceof Error ? error.message : String(error),
54+
});
55+
});
56+
return;
57+
}
58+
59+
// Required mode
60+
if (options.writer) {
61+
await options.writer.write(
62+
`event: log\ndata: ${JSON.stringify({ message: "Building compute template..." })}\n\n`
63+
);
64+
}
65+
66+
logger.info("Creating compute template (required mode)", {
67+
id: options.deploymentFriendlyId,
68+
imageReference: options.imageReference,
69+
});
70+
71+
const result = await this.createTemplate(options.imageReference);
72+
73+
if (!result.success) {
74+
logger.error("Compute template creation failed", {
75+
id: options.deploymentFriendlyId,
76+
imageReference: options.imageReference,
77+
error: result.error,
78+
});
79+
80+
const failService = new FailDeploymentService();
81+
await failService.call(options.authenticatedEnv, options.deploymentFriendlyId, {
82+
error: {
83+
name: "TemplateCreationFailed",
84+
message: `Failed to create compute template: ${result.error}`,
85+
},
86+
});
87+
88+
throw new ServiceValidationError(
89+
`Compute template creation failed: ${result.error}`
90+
);
91+
}
92+
93+
logger.info("Compute template created", {
94+
id: options.deploymentFriendlyId,
95+
imageReference: options.imageReference,
96+
});
97+
}
98+
2299
async resolveMode(
23100
projectId: string,
24101
prisma: PrismaClientOrTransaction

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

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { TimeoutDeploymentService } from "./timeoutDeployment.server";
1212
import { DeploymentService } from "./deployment.server";
1313
import { engine } from "../runEngine.server";
1414
import { tryCatch } from "@trigger.dev/core";
15-
import { ComputeTemplateCreationService } from "./computeTemplateCreation.server";
1615

1716
export class FinalizeDeploymentService extends BaseService {
1817
public async call(
@@ -66,47 +65,6 @@ export class FinalizeDeploymentService extends BaseService {
6665

6766
const imageDigest = validatedImageDigest(body.imageDigest);
6867

69-
// Compute template creation (before setting DEPLOYED)
70-
const templateService = new ComputeTemplateCreationService();
71-
const templateMode = await templateService.resolveMode(
72-
authenticatedEnv.projectId,
73-
this._prisma
74-
);
75-
76-
if (templateMode === "required" && deployment.imageReference) {
77-
logger.info("Creating compute template (required mode)", {
78-
id,
79-
imageReference: deployment.imageReference,
80-
});
81-
82-
const templateResult = await templateService.createTemplate(deployment.imageReference);
83-
84-
if (!templateResult.success) {
85-
logger.error("Compute template creation failed", {
86-
id,
87-
imageReference: deployment.imageReference,
88-
error: templateResult.error,
89-
});
90-
91-
const failService = new FailDeploymentService();
92-
await failService.call(authenticatedEnv, deployment.friendlyId, {
93-
error: {
94-
name: "TemplateCreationFailed",
95-
message: `Failed to create compute template: ${templateResult.error}`,
96-
},
97-
});
98-
99-
throw new ServiceValidationError(
100-
`Compute template creation failed: ${templateResult.error}`
101-
);
102-
}
103-
104-
logger.info("Compute template created", {
105-
id,
106-
imageReference: deployment.imageReference,
107-
});
108-
}
109-
11068
// Link the deployment with the background worker
11169
const finalizedDeployment = await this._prisma.workerDeployment.update({
11270
where: {
@@ -189,17 +147,6 @@ export class FinalizeDeploymentService extends BaseService {
189147

190148
await PerformDeploymentAlertsService.enqueue(deployment.id);
191149

192-
// Shadow mode: fire-and-forget template creation after deploy is finalized
193-
if (templateMode === "shadow" && deployment.imageReference) {
194-
templateService.createTemplate(deployment.imageReference, { background: true }).catch((error) => {
195-
logger.error("Shadow compute template creation failed", {
196-
id,
197-
imageReference: deployment.imageReference,
198-
error: error instanceof Error ? error.message : String(error),
199-
});
200-
});
201-
}
202-
203150
return finalizedDeployment;
204151
}
205152
}

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

Lines changed: 25 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import { mkdtemp, writeFile } from "node:fs/promises";
1111
import { env } from "~/env.server";
1212
import { depot as execDepot } from "@depot/cli";
1313
import { FinalizeDeploymentService } from "./finalizeDeployment.server";
14-
import { FailDeploymentService } from "./failDeployment.server";
1514
import { remoteBuildsEnabled } from "../remoteImageBuilder.server";
1615
import { getEcrAuthToken, isEcrRegistry } from "../getDeploymentImageRef.server";
1716
import { tryCatch } from "@trigger.dev/core";
@@ -25,12 +24,6 @@ export class FinalizeDeploymentV2Service extends BaseService {
2524
body: FinalizeDeploymentRequestBody,
2625
writer?: WritableStreamDefaultWriter
2726
) {
28-
// If remote builds are not enabled, lets just use the v1 finalize deployment service
29-
if (!remoteBuildsEnabled()) {
30-
const finalizeService = new FinalizeDeploymentService();
31-
return finalizeService.call(authenticatedEnv, id, body);
32-
}
33-
3427
const deployment = await this._prisma.workerDeployment.findFirst({
3528
where: {
3629
friendlyId: id,
@@ -64,7 +57,6 @@ export class FinalizeDeploymentV2Service extends BaseService {
6457

6558
if (deployment.status === "DEPLOYED") {
6659
logger.debug("Worker deployment is already deployed", { id });
67-
6860
return deployment;
6961
}
7062

@@ -74,32 +66,17 @@ export class FinalizeDeploymentV2Service extends BaseService {
7466
}
7567

7668
const finalizeService = new FinalizeDeploymentService();
77-
const templateService = new ComputeTemplateCreationService();
78-
79-
if (body.skipPushToRegistry) {
80-
logger.debug("Skipping push to registry during deployment finalization", {
81-
deployment,
82-
});
8369

84-
let templateMode: "required" | "shadow" | "skip" = "skip";
85-
if (deployment.imageReference) {
86-
templateMode = await this.#handleTemplateCreation({
87-
templateService,
88-
projectId: deployment.worker.project.id,
89-
imageReference: deployment.imageReference,
90-
deploymentFriendlyId: id,
91-
authenticatedEnv,
92-
writer,
70+
// If remote builds are not enabled, skip image push and go straight to template + finalize
71+
if (!remoteBuildsEnabled() || body.skipPushToRegistry) {
72+
if (body.skipPushToRegistry) {
73+
logger.debug("Skipping push to registry during deployment finalization", {
74+
deployment,
9375
});
9476
}
9577

96-
const result = await finalizeService.call(authenticatedEnv, id, body);
97-
98-
if (templateMode === "shadow" && deployment.imageReference) {
99-
this.#fireShadowTemplateCreation(templateService, deployment.imageReference, id);
100-
}
101-
102-
return result;
78+
await this.#createTemplateIfNeeded(deployment, id, authenticatedEnv, writer);
79+
return finalizeService.call(authenticatedEnv, id, body);
10380
}
10481

10582
const externalBuildData = deployment.externalBuildData
@@ -165,88 +142,28 @@ export class FinalizeDeploymentV2Service extends BaseService {
165142
pushedImage: pushResult.image,
166143
});
167144

168-
const templateMode = await this.#handleTemplateCreation({
169-
templateService,
170-
projectId: deployment.worker.project.id,
171-
imageReference: deployment.imageReference,
172-
deploymentFriendlyId: id,
173-
authenticatedEnv,
174-
writer,
175-
});
176-
177-
const finalizedDeployment = await finalizeService.call(authenticatedEnv, id, body);
178-
179-
// Shadow mode: fire-and-forget template creation after deploy is finalized
180-
if (templateMode === "shadow") {
181-
this.#fireShadowTemplateCreation(templateService, deployment.imageReference, id);
182-
}
183-
184-
return finalizedDeployment;
145+
await this.#createTemplateIfNeeded(deployment, id, authenticatedEnv, writer);
146+
return finalizeService.call(authenticatedEnv, id, body);
185147
}
186148

187-
async #handleTemplateCreation(options: {
188-
templateService: ComputeTemplateCreationService;
189-
projectId: string;
190-
imageReference: string;
191-
deploymentFriendlyId: string;
192-
authenticatedEnv: AuthenticatedEnvironment;
193-
writer?: WritableStreamDefaultWriter;
194-
}): Promise<"required" | "shadow" | "skip"> {
195-
const { templateService, projectId, imageReference, deploymentFriendlyId, authenticatedEnv, writer } = options;
196-
197-
const mode = await templateService.resolveMode(projectId, this._prisma);
198-
199-
if (mode !== "required") {
200-
return mode;
201-
}
202-
203-
if (writer) {
204-
await writer.write(
205-
`event: log\ndata: ${JSON.stringify({ message: "Building compute template..." })}\n\n`
206-
);
207-
}
208-
209-
const templateResult = await templateService.createTemplate(imageReference);
210-
211-
if (!templateResult.success) {
212-
logger.error("Compute template creation failed", {
213-
id: deploymentFriendlyId,
214-
imageReference,
215-
error: templateResult.error,
216-
});
217-
218-
const failService = new FailDeploymentService();
219-
await failService.call(authenticatedEnv, deploymentFriendlyId, {
220-
error: {
221-
name: "TemplateCreationFailed",
222-
message: `Failed to create compute template: ${templateResult.error}`,
223-
},
224-
});
225-
226-
throw new ServiceValidationError(
227-
`Compute template creation failed: ${templateResult.error}`
228-
);
149+
async #createTemplateIfNeeded(
150+
deployment: { imageReference: string | null; worker: { project: { id: string } } | null },
151+
deploymentFriendlyId: string,
152+
authenticatedEnv: AuthenticatedEnvironment,
153+
writer?: WritableStreamDefaultWriter
154+
): Promise<void> {
155+
if (!deployment.imageReference || !deployment.worker) {
156+
return;
229157
}
230158

231-
logger.debug("Compute template created", {
232-
id: deploymentFriendlyId,
233-
imageReference,
234-
});
235-
236-
return mode;
237-
}
238-
239-
#fireShadowTemplateCreation(
240-
templateService: ComputeTemplateCreationService,
241-
imageReference: string,
242-
deploymentFriendlyId: string
243-
) {
244-
templateService.createTemplate(imageReference, { background: true }).catch((error) => {
245-
logger.error("Shadow compute template creation failed", {
246-
id: deploymentFriendlyId,
247-
imageReference,
248-
error: error instanceof Error ? error.message : String(error),
249-
});
159+
const templateService = new ComputeTemplateCreationService();
160+
await templateService.handleDeployTemplate({
161+
projectId: deployment.worker.project.id,
162+
imageReference: deployment.imageReference,
163+
deploymentFriendlyId,
164+
authenticatedEnv,
165+
prisma: this._prisma,
166+
writer,
250167
});
251168
}
252169
}

0 commit comments

Comments
 (0)