@@ -519,7 +519,10 @@ export class LoggingSession {
519519 } )
520520
521521 this . completed = true
522- this . emitExecutionCompletedMetric ( 'failed' , Math . max ( 1 , durationMs ) )
522+ this . emitExecutionCompletedMetric (
523+ 'failed' ,
524+ typeof totalDurationMs === 'number' ? Math . max ( 1 , totalDurationMs ) : undefined
525+ )
523526
524527 try {
525528 const { PlatformEvents, createOTelSpansForWorkflowExecution } = await import (
@@ -613,7 +616,10 @@ export class LoggingSession {
613616 } )
614617
615618 this . completed = true
616- this . emitExecutionCompletedMetric ( 'cancelled' , Math . max ( 1 , durationMs ) )
619+ this . emitExecutionCompletedMetric (
620+ 'cancelled' ,
621+ typeof totalDurationMs === 'number' ? Math . max ( 1 , totalDurationMs ) : undefined
622+ )
617623
618624 try {
619625 const { PlatformEvents, createOTelSpansForWorkflowExecution } = await import (
@@ -992,7 +998,10 @@ export class LoggingSession {
992998 this . requestId ,
993999 this . workflowId
9941000 )
995- this . emitExecutionCompletedMetric ( 'failed' )
1001+ // The static helper emits the failure metric when the row transitions from
1002+ // a non-terminal status; mark this session as emitted either way so a later
1003+ // in-process completion attempt can't add a second point.
1004+ this . completionMetricEmitted = true
9961005 }
9971006
9981007 static async markExecutionAsFailed (
@@ -1003,6 +1012,21 @@ export class LoggingSession {
10031012 ) : Promise < void > {
10041013 try {
10051014 const message = errorMessage || 'Run failed'
1015+ const current = await db
1016+ . select ( {
1017+ status : workflowExecutionLogs . status ,
1018+ trigger : workflowExecutionLogs . trigger ,
1019+ } )
1020+ . from ( workflowExecutionLogs )
1021+ . where (
1022+ and (
1023+ eq ( workflowExecutionLogs . executionId , executionId ) ,
1024+ eq ( workflowExecutionLogs . workflowId , workflowId )
1025+ )
1026+ )
1027+ . limit ( 1 )
1028+ . then ( ( rows ) => rows [ 0 ] )
1029+
10061030 await db
10071031 . update ( workflowExecutionLogs )
10081032 . set ( {
@@ -1029,6 +1053,12 @@ export class LoggingSession {
10291053 )
10301054 )
10311055
1056+ // Only a transition from a non-terminal status is a new terminal outcome;
1057+ // rows already completed/failed/cancelled emitted their point elsewhere.
1058+ if ( current && ( current . status === 'running' || current . status === 'pending' ) ) {
1059+ workflowMetrics . recordExecutionCompleted ( { trigger : current . trigger , status : 'failed' } )
1060+ }
1061+
10321062 logger . info ( `[${ requestId || 'unknown' } ] Marked execution ${ executionId } as failed` )
10331063 } catch ( error ) {
10341064 logger . error ( `Failed to mark execution ${ executionId } as failed:` , {
0 commit comments