1+ import { isExecutionCancelled , isRedisCancellationEnabled } from '@/lib/execution/cancellation'
12import { createLogger } from '@/lib/logs/console/logger'
23import { BlockType } from '@/executor/constants'
34import type { DAG } from '@/executor/dag/builder'
@@ -23,6 +24,10 @@ export class ExecutionEngine {
2324 private finalOutput : NormalizedBlockOutput = { }
2425 private pausedBlocks : Map < string , PauseMetadata > = new Map ( )
2526 private allowResumeTriggers : boolean
27+ private cancelledFlag = false
28+ private lastCancellationCheck = 0
29+ private readonly useRedisCancellation : boolean
30+ private readonly CANCELLATION_CHECK_INTERVAL_MS = 500
2631
2732 constructor (
2833 private context : ExecutionContext ,
@@ -31,6 +36,35 @@ export class ExecutionEngine {
3136 private nodeOrchestrator : NodeExecutionOrchestrator
3237 ) {
3338 this . allowResumeTriggers = this . context . metadata . resumeFromSnapshot === true
39+ this . useRedisCancellation = isRedisCancellationEnabled ( ) && ! ! this . context . executionId
40+ }
41+
42+ private async checkCancellation ( ) : Promise < boolean > {
43+ if ( this . cancelledFlag ) {
44+ return true
45+ }
46+
47+ if ( this . useRedisCancellation ) {
48+ const now = Date . now ( )
49+ if ( now - this . lastCancellationCheck < this . CANCELLATION_CHECK_INTERVAL_MS ) {
50+ return false
51+ }
52+ this . lastCancellationCheck = now
53+
54+ const cancelled = await isExecutionCancelled ( this . context . executionId ! )
55+ if ( cancelled ) {
56+ this . cancelledFlag = true
57+ logger . info ( 'Execution cancelled via Redis' , { executionId : this . context . executionId } )
58+ }
59+ return cancelled
60+ }
61+
62+ if ( this . context . abortSignal ?. aborted ) {
63+ this . cancelledFlag = true
64+ return true
65+ }
66+
67+ return false
3468 }
3569
3670 async run ( triggerBlockId ?: string ) : Promise < ExecutionResult > {
@@ -39,7 +73,7 @@ export class ExecutionEngine {
3973 this . initializeQueue ( triggerBlockId )
4074
4175 while ( this . hasWork ( ) ) {
42- if ( this . context . abortSignal ?. aborted && this . executing . size === 0 ) {
76+ if ( ( await this . checkCancellation ( ) ) && this . executing . size === 0 ) {
4377 break
4478 }
4579 await this . processQueue ( )
@@ -54,7 +88,7 @@ export class ExecutionEngine {
5488 this . context . metadata . endTime = new Date ( endTime ) . toISOString ( )
5589 this . context . metadata . duration = endTime - startTime
5690
57- if ( this . context . abortSignal ?. aborted ) {
91+ if ( this . cancelledFlag ) {
5892 return {
5993 success : false ,
6094 output : this . finalOutput ,
@@ -75,7 +109,7 @@ export class ExecutionEngine {
75109 this . context . metadata . endTime = new Date ( endTime ) . toISOString ( )
76110 this . context . metadata . duration = endTime - startTime
77111
78- if ( this . context . abortSignal ?. aborted ) {
112+ if ( this . cancelledFlag ) {
79113 return {
80114 success : false ,
81115 output : this . finalOutput ,
@@ -234,7 +268,7 @@ export class ExecutionEngine {
234268
235269 private async processQueue ( ) : Promise < void > {
236270 while ( this . readyQueue . length > 0 ) {
237- if ( this . context . abortSignal ?. aborted ) {
271+ if ( await this . checkCancellation ( ) ) {
238272 break
239273 }
240274 const nodeId = this . dequeue ( )
0 commit comments