@@ -261,6 +261,60 @@ async function sendBuildFailureAlert(
261261 } ) ;
262262}
263263
264+ type CronFailureAlertOptions = {
265+ to : string ;
266+ serviceId : string ;
267+ path : string ;
268+ statusCode : number | null ;
269+ error : string | null ;
270+ } ;
271+
272+ async function sendCronFailureAlert (
273+ options : CronFailureAlertOptions ,
274+ ) : Promise < void > {
275+ const [ result ] = await db
276+ . select ( {
277+ serviceName : services . name ,
278+ projectName : projects . name ,
279+ projectSlug : projects . slug ,
280+ envName : environments . name ,
281+ } )
282+ . from ( services )
283+ . innerJoin ( projects , eq ( projects . id , services . projectId ) )
284+ . innerJoin ( environments , eq ( environments . id , services . environmentId ) )
285+ . where ( eq ( services . id , options . serviceId ) ) ;
286+
287+ if ( ! result ) return ;
288+
289+ const baseUrl = getAppBaseUrl ( ) ;
290+ const serviceUrl = baseUrl
291+ ? `${ baseUrl } /dashboard/projects/${ result . projectSlug } /${ result . envName } /services/${ options . serviceId } `
292+ : undefined ;
293+ const details = [
294+ { label : "Service" , value : result . serviceName } ,
295+ { label : "Project" , value : result . projectName } ,
296+ { label : "Cron Path" , value : options . path } ,
297+ ...( options . statusCode !== null
298+ ? [ { label : "HTTP Status" , value : String ( options . statusCode ) } ]
299+ : [ ] ) ,
300+ ...( options . error ? [ { label : "Error" , value : options . error } ] : [ ] ) ,
301+ ] ;
302+
303+ await sendAlert ( {
304+ to : options . to ,
305+ subject : `Cron Failed: ${ result . serviceName } ` ,
306+ template : Alert ( {
307+ bannerText : "CRON FAILED" ,
308+ heading : "Cron Failure Alert" ,
309+ description : `The cron job "${ options . path } " for service "${ result . serviceName } " in project "${ result . projectName } " has failed.` ,
310+ details,
311+ buttonText : serviceUrl ? "View Service" : undefined ,
312+ buttonUrl : serviceUrl ,
313+ baseUrl,
314+ } ) ,
315+ } ) ;
316+ }
317+
264318type DeploymentFailureAlertOptions = {
265319 to : string ;
266320 serviceId : string ;
@@ -400,6 +454,9 @@ export async function deliverNotificationEmail(
400454 case "build.failed" :
401455 await sendBuildFailureAlert ( { ...event , to } ) ;
402456 return ;
457+ case "cron.failed" :
458+ await sendCronFailureAlert ( { ...event , to } ) ;
459+ return ;
403460 case "deployment.failed" :
404461 await sendDeploymentFailureAlert ( { ...event , to } ) ;
405462 }
0 commit comments