Skip to content

Commit 50cf672

Browse files
committed
feat(webapp): integrate template creation into deploy finalize flow
1 parent d0149e9 commit 50cf672

File tree

1 file changed

+102
-1
lines changed

1 file changed

+102
-1
lines changed

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

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ 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";
1415
import { remoteBuildsEnabled } from "../remoteImageBuilder.server";
1516
import { getEcrAuthToken, isEcrRegistry } from "../getDeploymentImageRef.server";
1617
import { tryCatch } from "@trigger.dev/core";
1718
import { getRegistryConfig, type RegistryConfig } from "../registryConfig.server";
19+
import { ComputeTemplateCreationService } from "./computeTemplateCreation.server";
1820

1921
export class FinalizeDeploymentV2Service extends BaseService {
2022
public async call(
@@ -77,7 +79,33 @@ export class FinalizeDeploymentV2Service extends BaseService {
7779
logger.debug("Skipping push to registry during deployment finalization", {
7880
deployment,
7981
});
80-
return await finalizeService.call(authenticatedEnv, id, body);
82+
83+
let templateMode: "required" | "shadow" | "skip" = "skip";
84+
if (deployment.imageReference) {
85+
templateMode = await this.#handleTemplateCreation({
86+
templateService: new ComputeTemplateCreationService(),
87+
projectId: deployment.worker.project.id,
88+
imageReference: deployment.imageReference,
89+
deploymentFriendlyId: id,
90+
authenticatedEnv,
91+
writer,
92+
});
93+
}
94+
95+
const result = await finalizeService.call(authenticatedEnv, id, body);
96+
97+
if (templateMode === "shadow" && deployment.imageReference) {
98+
const shadowService = new ComputeTemplateCreationService();
99+
shadowService.createTemplate(deployment.imageReference).catch((error) => {
100+
logger.error("Shadow compute template creation failed", {
101+
id,
102+
imageReference: deployment.imageReference,
103+
error: error instanceof Error ? error.message : String(error),
104+
});
105+
});
106+
}
107+
108+
return result;
81109
}
82110

83111
const externalBuildData = deployment.externalBuildData
@@ -143,10 +171,83 @@ export class FinalizeDeploymentV2Service extends BaseService {
143171
pushedImage: pushResult.image,
144172
});
145173

174+
const templateMode = await this.#handleTemplateCreation({
175+
templateService: new ComputeTemplateCreationService(),
176+
projectId: deployment.worker.project.id,
177+
imageReference: deployment.imageReference,
178+
deploymentFriendlyId: id,
179+
authenticatedEnv,
180+
writer,
181+
});
182+
146183
const finalizedDeployment = await finalizeService.call(authenticatedEnv, id, body);
147184

185+
// Shadow mode: fire-and-forget template creation after deploy is finalized
186+
if (templateMode === "shadow") {
187+
const shadowService = new ComputeTemplateCreationService();
188+
shadowService.createTemplate(deployment.imageReference).catch((error) => {
189+
logger.error("Shadow compute template creation failed", {
190+
id,
191+
imageReference: deployment.imageReference,
192+
error: error instanceof Error ? error.message : String(error),
193+
});
194+
});
195+
}
196+
148197
return finalizedDeployment;
149198
}
199+
200+
async #handleTemplateCreation(options: {
201+
templateService: ComputeTemplateCreationService;
202+
projectId: string;
203+
imageReference: string;
204+
deploymentFriendlyId: string;
205+
authenticatedEnv: AuthenticatedEnvironment;
206+
writer?: WritableStreamDefaultWriter;
207+
}): Promise<"required" | "shadow" | "skip"> {
208+
const { templateService, projectId, imageReference, deploymentFriendlyId, authenticatedEnv, writer } = options;
209+
210+
const mode = await templateService.resolveMode(projectId, this._prisma);
211+
212+
if (mode !== "required") {
213+
return mode;
214+
}
215+
216+
if (writer) {
217+
await writer.write(
218+
`event: log\ndata: ${JSON.stringify({ message: "Building compute template..." })}\n\n`
219+
);
220+
}
221+
222+
const templateResult = await templateService.createTemplate(imageReference);
223+
224+
if (!templateResult.success) {
225+
logger.error("Compute template creation failed", {
226+
id: deploymentFriendlyId,
227+
imageReference,
228+
error: templateResult.error,
229+
});
230+
231+
const failService = new FailDeploymentService();
232+
await failService.call(authenticatedEnv, deploymentFriendlyId, {
233+
error: {
234+
name: "TemplateCreationFailed",
235+
message: `Failed to create compute template: ${templateResult.error}`,
236+
},
237+
});
238+
239+
throw new ServiceValidationError(
240+
`Compute template creation failed: ${templateResult.error}`
241+
);
242+
}
243+
244+
logger.debug("Compute template created", {
245+
id: deploymentFriendlyId,
246+
imageReference,
247+
});
248+
249+
return mode;
250+
}
150251
}
151252

152253
type ExecutePushToRegistryOptions = {

0 commit comments

Comments
 (0)