@mastra/inngest 0.11.0-alpha.3 → 0.11.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -33,13 +33,17 @@ export type InngestEngineType = {
33
33
 
34
34
  export function serve({ mastra, inngest }: { mastra: Mastra; inngest: Inngest }): ReturnType<typeof inngestServe> {
35
35
  const wfs = mastra.getWorkflows();
36
- const functions = Object.values(wfs).flatMap(wf => {
37
- if (wf instanceof InngestWorkflow) {
38
- wf.__registerMastra(mastra);
39
- return wf.getFunctions();
40
- }
41
- return [];
42
- });
36
+ const functions = Array.from(
37
+ new Set(
38
+ Object.values(wfs).flatMap(wf => {
39
+ if (wf instanceof InngestWorkflow) {
40
+ wf.__registerMastra(mastra);
41
+ return wf.getFunctions();
42
+ }
43
+ return [];
44
+ }),
45
+ ),
46
+ );
43
47
  return inngestServe({
44
48
  client: inngest,
45
49
  functions,
@@ -94,8 +98,14 @@ export class InngestRun<
94
98
  while (runs?.[0]?.status !== 'Completed' || runs?.[0]?.event_id !== eventId) {
95
99
  await new Promise(resolve => setTimeout(resolve, 1000));
96
100
  runs = await this.getRuns(eventId);
97
- if (runs?.[0]?.status === 'Failed' || runs?.[0]?.status === 'Cancelled') {
101
+ if (runs?.[0]?.status === 'Failed') {
98
102
  throw new Error(`Function run ${runs?.[0]?.status}`);
103
+ } else if (runs?.[0]?.status === 'Cancelled') {
104
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
105
+ workflowName: this.workflowId,
106
+ runId: this.runId,
107
+ });
108
+ return { output: { result: { steps: snapshot?.context, status: 'canceled' } } };
99
109
  }
100
110
  }
101
111
  return runs?.[0];
@@ -108,6 +118,30 @@ export class InngestRun<
108
118
  });
109
119
  }
110
120
 
121
+ async cancel() {
122
+ await this.inngest.send({
123
+ name: `cancel.workflow.${this.workflowId}`,
124
+ data: {
125
+ runId: this.runId,
126
+ },
127
+ });
128
+
129
+ const snapshot = await this.#mastra?.storage?.loadWorkflowSnapshot({
130
+ workflowName: this.workflowId,
131
+ runId: this.runId,
132
+ });
133
+ if (snapshot) {
134
+ await this.#mastra?.storage?.persistWorkflowSnapshot({
135
+ workflowName: this.workflowId,
136
+ runId: this.runId,
137
+ snapshot: {
138
+ ...snapshot,
139
+ status: 'canceled' as any,
140
+ },
141
+ });
142
+ }
143
+ }
144
+
111
145
  async start({
112
146
  inputData,
113
147
  }: {
@@ -147,7 +181,9 @@ export class InngestRun<
147
181
  result.error = new Error(result.error);
148
182
  }
149
183
 
150
- this.cleanup?.();
184
+ if (result.status !== 'suspended') {
185
+ this.cleanup?.();
186
+ }
151
187
  return result;
152
188
  }
153
189
 
@@ -432,23 +468,27 @@ export class InngestWorkflow<
432
468
 
433
469
  this.runs.set(runIdToUse, run);
434
470
 
435
- await this.mastra?.getStorage()?.persistWorkflowSnapshot({
436
- workflowName: this.id,
437
- runId: runIdToUse,
438
- snapshot: {
471
+ const workflowSnapshotInStorage = await this.getWorkflowRunExecutionResult(runIdToUse);
472
+
473
+ if (!workflowSnapshotInStorage) {
474
+ await this.mastra?.getStorage()?.persistWorkflowSnapshot({
475
+ workflowName: this.id,
439
476
  runId: runIdToUse,
440
- status: 'pending',
441
- value: {},
442
- context: {},
443
- activePaths: [],
444
- serializedStepGraph: this.serializedStepGraph,
445
- suspendedPaths: {},
446
- result: undefined,
447
- error: undefined,
448
- // @ts-ignore
449
- timestamp: Date.now(),
450
- },
451
- });
477
+ snapshot: {
478
+ runId: runIdToUse,
479
+ status: 'pending',
480
+ value: {},
481
+ context: {},
482
+ activePaths: [],
483
+ serializedStepGraph: this.serializedStepGraph,
484
+ suspendedPaths: {},
485
+ result: undefined,
486
+ error: undefined,
487
+ // @ts-ignore
488
+ timestamp: Date.now(),
489
+ },
490
+ });
491
+ }
452
492
 
453
493
  return run;
454
494
  }
@@ -458,8 +498,12 @@ export class InngestWorkflow<
458
498
  return this.function;
459
499
  }
460
500
  this.function = this.inngest.createFunction(
461
- // @ts-ignore
462
- { id: `workflow.${this.id}`, retries: this.retryConfig?.attempts ?? 0 },
501
+ {
502
+ id: `workflow.${this.id}`,
503
+ // @ts-ignore
504
+ retries: this.retryConfig?.attempts ?? 0,
505
+ cancelOn: [{ event: `cancel.workflow.${this.id}` }],
506
+ },
463
507
  { event: `workflow.${this.id}` },
464
508
  async ({ event, step, attempt, publish }) => {
465
509
  let { inputData, runId, resume } = event.data;
@@ -508,6 +552,7 @@ export class InngestWorkflow<
508
552
  retryConfig: this.retryConfig,
509
553
  runtimeContext: new RuntimeContext(), // TODO
510
554
  resume,
555
+ abortController: new AbortController(),
511
556
  });
512
557
 
513
558
  return { result, runId };
@@ -630,7 +675,7 @@ export function createStep<
630
675
  outputSchema: z.object({
631
676
  text: z.string(),
632
677
  }),
633
- execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext }) => {
678
+ execute: async ({ inputData, [EMITTER_SYMBOL]: emitter, runtimeContext, abortSignal, abort }) => {
634
679
  let streamPromise = {} as {
635
680
  promise: Promise<string>;
636
681
  resolve: (value: string) => void;
@@ -656,8 +701,13 @@ export function createStep<
656
701
  onFinish: result => {
657
702
  streamPromise.resolve(result.text);
658
703
  },
704
+ abortSignal,
659
705
  });
660
706
 
707
+ if (abortSignal.aborted) {
708
+ return abort();
709
+ }
710
+
661
711
  for await (const chunk of fullStream) {
662
712
  switch (chunk.type) {
663
713
  case 'text-delta':
@@ -815,6 +865,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
815
865
  delay?: number;
816
866
  };
817
867
  runtimeContext: RuntimeContext;
868
+ abortController: AbortController;
818
869
  }): Promise<TOutput> {
819
870
  await params.emitter.emit('watch-v2', {
820
871
  type: 'start',
@@ -914,6 +965,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
914
965
  resume,
915
966
  prevOutput,
916
967
  emitter,
968
+ abortController,
917
969
  runtimeContext,
918
970
  }: {
919
971
  workflowId: string;
@@ -927,6 +979,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
927
979
  };
928
980
  prevOutput: any;
929
981
  emitter: Emitter;
982
+ abortController: AbortController;
930
983
  runtimeContext: RuntimeContext;
931
984
  }): Promise<StepResult<any, any, any, any>> {
932
985
  return super.executeStep({
@@ -938,6 +991,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
938
991
  resume,
939
992
  prevOutput,
940
993
  emitter,
994
+ abortController,
941
995
  runtimeContext,
942
996
  });
943
997
  }
@@ -966,17 +1020,12 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
966
1020
  resume,
967
1021
  prevOutput,
968
1022
  emitter,
1023
+ abortController,
969
1024
  runtimeContext,
970
1025
  }: {
971
1026
  step: Step<string, any, any>;
972
1027
  stepResults: Record<string, StepResult<any, any, any, any>>;
973
- executionContext: {
974
- workflowId: string;
975
- runId: string;
976
- executionPath: number[];
977
- suspendedPaths: Record<string, number[]>;
978
- retryConfig: { attempts: number; delay: number };
979
- };
1028
+ executionContext: ExecutionContext;
980
1029
  resume?: {
981
1030
  steps: string[];
982
1031
  resumePayload: any;
@@ -984,6 +1033,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
984
1033
  };
985
1034
  prevOutput: any;
986
1035
  emitter: Emitter;
1036
+ abortController: AbortController;
987
1037
  runtimeContext: RuntimeContext;
988
1038
  }): Promise<StepResult<any, any, any, any>> {
989
1039
  const startedAt = await this.inngestStep.run(
@@ -1016,6 +1066,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1016
1066
  type: 'step-start',
1017
1067
  payload: {
1018
1068
  id: step.id,
1069
+ status: 'running',
1019
1070
  },
1020
1071
  });
1021
1072
 
@@ -1091,6 +1142,8 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1091
1142
  payload: {
1092
1143
  id: step.id,
1093
1144
  status: 'failed',
1145
+ error: result?.error,
1146
+ payload: prevOutput,
1094
1147
  },
1095
1148
  });
1096
1149
 
@@ -1128,6 +1181,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1128
1181
  type: 'step-suspended',
1129
1182
  payload: {
1130
1183
  id: step.id,
1184
+ status: 'suspended',
1131
1185
  },
1132
1186
  });
1133
1187
 
@@ -1187,6 +1241,15 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1187
1241
  eventTimestamp: Date.now(),
1188
1242
  });
1189
1243
 
1244
+ await emitter.emit('watch-v2', {
1245
+ type: 'step-result',
1246
+ payload: {
1247
+ id: step.id,
1248
+ status: 'success',
1249
+ output: result?.result,
1250
+ },
1251
+ });
1252
+
1190
1253
  await emitter.emit('watch-v2', {
1191
1254
  type: 'step-finish',
1192
1255
  payload: {
@@ -1241,6 +1304,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1241
1304
  engine: {
1242
1305
  step: this.inngestStep,
1243
1306
  },
1307
+ abortSignal: abortController.signal,
1244
1308
  });
1245
1309
  const endedAt = Date.now();
1246
1310
 
@@ -1307,8 +1371,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1307
1371
  type: 'step-suspended',
1308
1372
  payload: {
1309
1373
  id: step.id,
1310
- status: execResults.status,
1311
- output: execResults.status === 'success' ? execResults?.output : undefined,
1374
+ ...execResults,
1312
1375
  },
1313
1376
  });
1314
1377
  } else {
@@ -1316,8 +1379,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1316
1379
  type: 'step-result',
1317
1380
  payload: {
1318
1381
  id: step.id,
1319
- status: execResults.status,
1320
- output: execResults.status === 'success' ? execResults?.output : undefined,
1382
+ ...execResults,
1321
1383
  },
1322
1384
  });
1323
1385
 
@@ -1396,6 +1458,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1396
1458
  resume,
1397
1459
  executionContext,
1398
1460
  emitter,
1461
+ abortController,
1399
1462
  runtimeContext,
1400
1463
  }: {
1401
1464
  workflowId: string;
@@ -1417,6 +1480,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1417
1480
  };
1418
1481
  executionContext: ExecutionContext;
1419
1482
  emitter: Emitter;
1483
+ abortController: AbortController;
1420
1484
  runtimeContext: RuntimeContext;
1421
1485
  }): Promise<StepResult<any, any, any, any>> {
1422
1486
  let execResults: any;
@@ -1429,6 +1493,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1429
1493
  runId,
1430
1494
  mastra: this.mastra!,
1431
1495
  runtimeContext,
1496
+ runCount: -1,
1432
1497
  inputData: prevOutput,
1433
1498
  getInitData: () => stepResults?.input as any,
1434
1499
  getStepResult: (step: any) => {
@@ -1447,10 +1512,14 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1447
1512
  // TODO: this function shouldn't have suspend probably?
1448
1513
  suspend: async (_suspendPayload: any) => {},
1449
1514
  bail: () => {},
1515
+ abort: () => {
1516
+ abortController.abort();
1517
+ },
1450
1518
  [EMITTER_SYMBOL]: emitter,
1451
1519
  engine: {
1452
1520
  step: this.inngestStep,
1453
1521
  },
1522
+ abortSignal: abortController.signal,
1454
1523
  });
1455
1524
  return result ? index : null;
1456
1525
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -1482,6 +1551,7 @@ export class InngestExecutionEngine extends DefaultExecutionEngine {
1482
1551
  executionSpan: executionContext.executionSpan,
1483
1552
  },
1484
1553
  emitter,
1554
+ abortController,
1485
1555
  runtimeContext,
1486
1556
  }),
1487
1557
  ),