@@ -11,10 +11,12 @@ import { mkdtemp, writeFile } from "node:fs/promises";
1111import { env } from "~/env.server" ;
1212import { depot as execDepot } from "@depot/cli" ;
1313import { FinalizeDeploymentService } from "./finalizeDeployment.server" ;
14+ import { FailDeploymentService } from "./failDeployment.server" ;
1415import { remoteBuildsEnabled } from "../remoteImageBuilder.server" ;
1516import { getEcrAuthToken , isEcrRegistry } from "../getDeploymentImageRef.server" ;
1617import { tryCatch } from "@trigger.dev/core" ;
1718import { getRegistryConfig , type RegistryConfig } from "../registryConfig.server" ;
19+ import { ComputeTemplateCreationService } from "./computeTemplateCreation.server" ;
1820
1921export 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
152253type ExecutePushToRegistryOptions = {
0 commit comments