inngest 4.3.0 → 4.4.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/CHANGELOG.md +14 -0
- package/api/schema.d.cts +2 -2
- package/api/schema.d.cts.map +1 -1
- package/api/schema.d.ts +2 -2
- package/api/schema.d.ts.map +1 -1
- package/components/DeferredFunction.cjs +66 -0
- package/components/DeferredFunction.cjs.map +1 -0
- package/components/DeferredFunction.d.cts +99 -0
- package/components/DeferredFunction.d.cts.map +1 -0
- package/components/DeferredFunction.d.ts +99 -0
- package/components/DeferredFunction.d.ts.map +1 -0
- package/components/DeferredFunction.js +65 -0
- package/components/DeferredFunction.js.map +1 -0
- package/components/Inngest.cjs +5 -2
- package/components/Inngest.cjs.map +1 -1
- package/components/Inngest.d.cts +4 -3
- package/components/Inngest.d.cts.map +1 -1
- package/components/Inngest.d.ts +4 -3
- package/components/Inngest.d.ts.map +1 -1
- package/components/Inngest.js +5 -2
- package/components/Inngest.js.map +1 -1
- package/components/InngestCommHandler.cjs +28 -23
- package/components/InngestCommHandler.cjs.map +1 -1
- package/components/InngestCommHandler.d.cts +9 -4
- package/components/InngestCommHandler.d.cts.map +1 -1
- package/components/InngestCommHandler.d.ts +9 -4
- package/components/InngestCommHandler.d.ts.map +1 -1
- package/components/InngestCommHandler.js +28 -23
- package/components/InngestCommHandler.js.map +1 -1
- package/components/InngestFunction.cjs +27 -19
- package/components/InngestFunction.cjs.map +1 -1
- package/components/InngestFunction.d.cts +6 -1
- package/components/InngestFunction.d.cts.map +1 -1
- package/components/InngestFunction.d.ts +6 -1
- package/components/InngestFunction.d.ts.map +1 -1
- package/components/InngestFunction.js +27 -19
- package/components/InngestFunction.js.map +1 -1
- package/components/InngestGroupTools.cjs +1 -1
- package/components/InngestGroupTools.cjs.map +1 -1
- package/components/InngestGroupTools.js +1 -1
- package/components/InngestGroupTools.js.map +1 -1
- package/components/connect/config.cjs +2 -0
- package/components/connect/config.cjs.map +1 -1
- package/components/connect/config.js +2 -0
- package/components/connect/config.js.map +1 -1
- package/components/execution/InngestExecution.cjs.map +1 -1
- package/components/execution/InngestExecution.d.cts +19 -2
- package/components/execution/InngestExecution.d.cts.map +1 -1
- package/components/execution/InngestExecution.d.ts +19 -2
- package/components/execution/InngestExecution.d.ts.map +1 -1
- package/components/execution/InngestExecution.js.map +1 -1
- package/components/execution/engine.cjs +232 -27
- package/components/execution/engine.cjs.map +1 -1
- package/components/execution/engine.d.cts +14 -0
- package/components/execution/engine.d.cts.map +1 -1
- package/components/execution/engine.d.ts +14 -0
- package/components/execution/engine.d.ts.map +1 -1
- package/components/execution/engine.js +232 -27
- package/components/execution/engine.js.map +1 -1
- package/components/execution/lazyOps.cjs +64 -0
- package/components/execution/lazyOps.cjs.map +1 -0
- package/components/execution/lazyOps.d.cts +42 -0
- package/components/execution/lazyOps.d.cts.map +1 -0
- package/components/execution/lazyOps.d.ts +42 -0
- package/components/execution/lazyOps.d.ts.map +1 -0
- package/components/execution/lazyOps.js +63 -0
- package/components/execution/lazyOps.js.map +1 -0
- package/components/execution/otel/middleware.d.cts +6 -3
- package/components/execution/otel/middleware.d.cts.map +1 -1
- package/components/execution/otel/middleware.d.ts +6 -3
- package/components/execution/otel/middleware.d.ts.map +1 -1
- package/components/middleware/middleware.cjs.map +1 -1
- package/components/middleware/middleware.d.cts +1 -1
- package/components/middleware/middleware.d.cts.map +1 -1
- package/components/middleware/middleware.d.ts +1 -1
- package/components/middleware/middleware.d.ts.map +1 -1
- package/components/middleware/middleware.js.map +1 -1
- package/components/middleware/utils.cjs +1 -0
- package/components/middleware/utils.cjs.map +1 -1
- package/components/middleware/utils.js +1 -0
- package/components/middleware/utils.js.map +1 -1
- package/components/realtime/types.d.cts +4 -4
- package/components/realtime/types.d.cts.map +1 -1
- package/components/realtime/types.d.ts +4 -4
- package/components/realtime/types.d.ts.map +1 -1
- package/components/triggers/typeHelpers.cjs.map +1 -1
- package/components/triggers/typeHelpers.d.cts +11 -0
- package/components/triggers/typeHelpers.d.cts.map +1 -1
- package/components/triggers/typeHelpers.d.ts +11 -0
- package/components/triggers/typeHelpers.d.ts.map +1 -1
- package/components/triggers/typeHelpers.js.map +1 -1
- package/experimental.cjs +3 -0
- package/experimental.d.cts +2 -1
- package/experimental.d.ts +2 -1
- package/experimental.js +2 -1
- package/helpers/consts.cjs +6 -0
- package/helpers/consts.cjs.map +1 -1
- package/helpers/consts.d.cts +6 -0
- package/helpers/consts.d.cts.map +1 -1
- package/helpers/consts.d.ts +6 -0
- package/helpers/consts.d.ts.map +1 -1
- package/helpers/consts.js +6 -0
- package/helpers/consts.js.map +1 -1
- package/helpers/functions.cjs +1 -0
- package/helpers/functions.cjs.map +1 -1
- package/helpers/functions.js +1 -0
- package/helpers/functions.js.map +1 -1
- package/helpers/marker.cjs +21 -0
- package/helpers/marker.cjs.map +1 -0
- package/helpers/marker.d.cts +12 -0
- package/helpers/marker.d.cts.map +1 -0
- package/helpers/marker.d.ts +12 -0
- package/helpers/marker.d.ts.map +1 -0
- package/helpers/marker.js +19 -0
- package/helpers/marker.js.map +1 -0
- package/package.json +2 -2
- package/proto/src/components/connect/protobuf/connect.cjs +11 -2
- package/proto/src/components/connect/protobuf/connect.cjs.map +1 -1
- package/proto/src/components/connect/protobuf/connect.js +11 -2
- package/proto/src/components/connect/protobuf/connect.js.map +1 -1
- package/types.cjs +2 -0
- package/types.cjs.map +1 -1
- package/types.d.cts +52 -18
- package/types.d.cts.map +1 -1
- package/types.d.ts +52 -18
- package/types.d.ts.map +1 -1
- package/types.js +2 -0
- package/types.js.map +1 -1
- package/version.cjs +1 -1
- package/version.cjs.map +1 -1
- package/version.d.cts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
|
@@ -4,6 +4,7 @@ import { MetadataUpdate } from "../InngestMetadata.cjs";
|
|
|
4
4
|
import { BasicFoundStep, InngestExecutionFactory, MemoizedOp } from "./InngestExecution.cjs";
|
|
5
5
|
import { OutgoingOp } from "../../types.cjs";
|
|
6
6
|
import { StepError } from "../StepError.cjs";
|
|
7
|
+
import { LazyOps } from "./lazyOps.cjs";
|
|
7
8
|
|
|
8
9
|
//#region src/components/execution/engine.d.ts
|
|
9
10
|
declare namespace engine_d_exports {
|
|
@@ -46,6 +47,13 @@ interface ExecutionState {
|
|
|
46
47
|
* with state from the executor.
|
|
47
48
|
*/
|
|
48
49
|
stepState: Record<string, MemoizedOp>;
|
|
50
|
+
/**
|
|
51
|
+
* Hashed defer step IDs the backend has already received. Used to skip
|
|
52
|
+
* re-emitting `DeferAdd` ops on replay. Defer ops aren't memoized like
|
|
53
|
+
* normal steps (they have no result), so this lives separately from
|
|
54
|
+
* `stepState`.
|
|
55
|
+
*/
|
|
56
|
+
priorDefers: Record<string, unknown>;
|
|
49
57
|
/**
|
|
50
58
|
* The number of steps we expect to fulfil based on the state passed from the
|
|
51
59
|
* Executor.
|
|
@@ -122,6 +130,12 @@ interface ExecutionState {
|
|
|
122
130
|
* A buffer of steps that are currently queued to be checkpointed.
|
|
123
131
|
*/
|
|
124
132
|
checkpointingStepBuffer: OutgoingOp[];
|
|
133
|
+
/**
|
|
134
|
+
* Buffer for opcode-only sync ops (e.g. `DeferAdd`) awaiting shipment
|
|
135
|
+
* on the next outbound wire message. See `ARCHITECTURE.md` and
|
|
136
|
+
* `lazyOps.ts` for the rationale.
|
|
137
|
+
*/
|
|
138
|
+
lazyOps: LazyOps;
|
|
125
139
|
/**
|
|
126
140
|
* Metadata collected during execution to be sent with outgoing ops.
|
|
127
141
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.cts","names":[],"sources":["../../../src/components/execution/engine.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.d.cts","names":[],"sources":["../../../src/components/execution/engine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;cA2Ha,uBAAuB;;;;UAmuFnB,WAAA;;YACU,cAAc;;;IApuF5B,KAAA,EAAA,OAAA;EAmuFI,CAAA;EAAW,mBAAA,EAAA;IACD,IAAA,EAAA,OAAA;;kBAIjB,EAAA;IACM,IAAA,EADN,UACM;IAAc,UAAA,EAAd,cAAc,EAAA;IAOzB,eAAU,EAAA,MAAA;EAAA,CAAA;iCACD,EAAA,CAAA,CAAA;yCAA+B,EAAA,CAAA,CAAA;;KADxC,UAAA,GAC0D,QAAnC,MAAd,WAAc,GAAA,QAAA,CAAA;EACpB,IAAA,EADqC,CACrC;AAAW,CAAA,GADgC,WAChC,CAD4C,CAC5C,CAAA,CAAA,EA+BnB,CAAA,MA/BQ,WA+BS,CAAA;AAAc,UAAd,cAAA,CAAc;;;;;;eAoBhB,CAAA,EAdG,QAcH,CAdY,IAcZ,CAdiB,UAcjB,EAAA,IAAA,CAAA,CAAA;;;;;WA8BS,EAtCX,MAsCW,CAAA,MAAA,EAtCI,UAsCJ,CAAA;;;;;;;aAsEX,EApGE,MAoGF,CAAA,MAAA,EAAA,OAAA,CAAA;EAAG;AACf;AAgBkC;;gBA4BjC,EAAA,MAAA;;;;;OAMU,EA3IH,GA2IG,CAAA,MAAA,EA3IS,SA2IT,CAAA;;;AAqCZ;;;UAjFiC,EAAA,OAAA;;;;;QAlFzB,eAAe;;;;wBAKC;;;;;;;;;;;;;;;0BAkBE;;;;;;;;;;;;;;;8BAgBI;;;;;;;;;;;;;;;;;;;;;2BAwBH;;;;;;WAOhB;;;;aAKE,YAAY,MAAM;;;;;UAiBrB,yBAAA;;;;;;;;;;;;;;;iBA2BD,sBAAA;;;;;;mBAMU;YACP,YAAY;IACpB;;;;cAoCS;eAjFO,eAAa"}
|
|
@@ -4,6 +4,7 @@ import { MetadataUpdate } from "../InngestMetadata.js";
|
|
|
4
4
|
import { BasicFoundStep, InngestExecutionFactory, MemoizedOp } from "./InngestExecution.js";
|
|
5
5
|
import { OutgoingOp } from "../../types.js";
|
|
6
6
|
import { StepError } from "../StepError.js";
|
|
7
|
+
import { LazyOps } from "./lazyOps.js";
|
|
7
8
|
|
|
8
9
|
//#region src/components/execution/engine.d.ts
|
|
9
10
|
declare namespace engine_d_exports {
|
|
@@ -46,6 +47,13 @@ interface ExecutionState {
|
|
|
46
47
|
* with state from the executor.
|
|
47
48
|
*/
|
|
48
49
|
stepState: Record<string, MemoizedOp>;
|
|
50
|
+
/**
|
|
51
|
+
* Hashed defer step IDs the backend has already received. Used to skip
|
|
52
|
+
* re-emitting `DeferAdd` ops on replay. Defer ops aren't memoized like
|
|
53
|
+
* normal steps (they have no result), so this lives separately from
|
|
54
|
+
* `stepState`.
|
|
55
|
+
*/
|
|
56
|
+
priorDefers: Record<string, unknown>;
|
|
49
57
|
/**
|
|
50
58
|
* The number of steps we expect to fulfil based on the state passed from the
|
|
51
59
|
* Executor.
|
|
@@ -122,6 +130,12 @@ interface ExecutionState {
|
|
|
122
130
|
* A buffer of steps that are currently queued to be checkpointed.
|
|
123
131
|
*/
|
|
124
132
|
checkpointingStepBuffer: OutgoingOp[];
|
|
133
|
+
/**
|
|
134
|
+
* Buffer for opcode-only sync ops (e.g. `DeferAdd`) awaiting shipment
|
|
135
|
+
* on the next outbound wire message. See `ARCHITECTURE.md` and
|
|
136
|
+
* `lazyOps.ts` for the rationale.
|
|
137
|
+
*/
|
|
138
|
+
lazyOps: LazyOps;
|
|
125
139
|
/**
|
|
126
140
|
* Metadata collected during execution to be sent with outgoing ops.
|
|
127
141
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","names":[],"sources":["../../../src/components/execution/engine.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"engine.d.ts","names":[],"sources":["../../../src/components/execution/engine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;cA2Ha,uBAAuB;;;;UAmuFnB,WAAA;;YACU,cAAc;;;IApuF5B,KAAA,EAAA,OAAA;EAmuFI,CAAA;EAAW,mBAAA,EAAA;IACD,IAAA,EAAA,OAAA;;kBAIjB,EAAA;IACM,IAAA,EADN,UACM;IAAc,UAAA,EAAd,cAAc,EAAA;IAOzB,eAAU,EAAA,MAAA;EAAA,CAAA;iCACD,EAAA,CAAA,CAAA;yCAA+B,EAAA,CAAA,CAAA;;KADxC,UAAA,GAC0D,QAAnC,MAAd,WAAc,GAAA,QAAA,CAAA;EACpB,IAAA,EADqC,CACrC;AAAW,CAAA,GADgC,WAChC,CAD4C,CAC5C,CAAA,CAAA,EA+BnB,CAAA,MA/BQ,WA+BS,CAAA;AAAc,UAAd,cAAA,CAAc;;;;;;eAoBhB,CAAA,EAdG,QAcH,CAdY,IAcZ,CAdiB,UAcjB,EAAA,IAAA,CAAA,CAAA;;;;;WA8BS,EAtCX,MAsCW,CAAA,MAAA,EAtCI,UAsCJ,CAAA;;;;;;;aAsEX,EApGE,MAoGF,CAAA,MAAA,EAAA,OAAA,CAAA;EAAG;AACf;AAgBkC;;gBA4BjC,EAAA,MAAA;;;;;OAMU,EA3IH,GA2IG,CAAA,MAAA,EA3IS,SA2IT,CAAA;;;AAqCZ;;;UAjFiC,EAAA,OAAA;;;;;QAlFzB,eAAe;;;;wBAKC;;;;;;;;;;;;;;;0BAkBE;;;;;;;;;;;;;;;8BAgBI;;;;;;;;;;;;;;;;;;;;;2BAwBH;;;;;;WAOhB;;;;aAKE,YAAY,MAAM;;;;;UAiBrB,yBAAA;;;;;;;;;;;;;;;iBA2BD,sBAAA;;;;;;mBAMU;YACP,YAAY;IACpB;;;;cAoCS;eAjFO,eAAa"}
|
|
@@ -7,6 +7,7 @@ import { StepMode, StepOpCode, jsonErrorSchema } from "../../types.js";
|
|
|
7
7
|
import { InngestExecution } from "./InngestExecution.js";
|
|
8
8
|
import { isRecord } from "../../helpers/types.js";
|
|
9
9
|
import { undefinedToNull } from "../../helpers/functions.js";
|
|
10
|
+
import { isDeferredFunction } from "../../helpers/marker.js";
|
|
10
11
|
import { isTemporalDuration } from "../../helpers/temporal.js";
|
|
11
12
|
import { createDeferredPromise, createDeferredPromiseWithStack, createTimeoutPromise, goIntervalTiming, resolveAfterPending, resolveNextTick, retryWithBackoff, runAsPromise } from "../../helpers/promises.js";
|
|
12
13
|
import { getAsyncCtx, getAsyncLocalStorage } from "./als.js";
|
|
@@ -20,6 +21,7 @@ import { StepError } from "../StepError.js";
|
|
|
20
21
|
import { buildSseMetadataEvent, prependToStream } from "./streaming.js";
|
|
21
22
|
import { Stream } from "../StreamTools.js";
|
|
22
23
|
import { validateEvents } from "../triggers/utils.js";
|
|
24
|
+
import { LazyOps, isLazyOp } from "./lazyOps.js";
|
|
23
25
|
import { clientProcessorMap } from "./otel/access.js";
|
|
24
26
|
import { z } from "zod/v3";
|
|
25
27
|
import hashjs from "hash.js";
|
|
@@ -258,6 +260,8 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
258
260
|
throw new Error("Core loop finished without returning a value");
|
|
259
261
|
}
|
|
260
262
|
async checkpoint(steps) {
|
|
263
|
+
const lazyOps = this.state.lazyOps.drain();
|
|
264
|
+
if (lazyOps.length > 0) steps = [...steps, ...lazyOps];
|
|
261
265
|
if (this.options.stepMode === StepMode.Sync) if (!this.state.checkpointedRun) {
|
|
262
266
|
const res = await retryWithBackoff(() => this.options.client["inngestApi"].checkpointNewRun({
|
|
263
267
|
runId: this.fnArg.runId,
|
|
@@ -515,12 +519,13 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
515
519
|
return transformResult;
|
|
516
520
|
};
|
|
517
521
|
const maybeReturnNewSteps = async () => {
|
|
518
|
-
const
|
|
519
|
-
if (
|
|
522
|
+
const allSteps = [...await this.filterNewSteps(Array.from(this.state.steps.values())) ?? [], ...this.state.lazyOps.drain()];
|
|
523
|
+
if (allSteps.length === 0) return;
|
|
524
|
+
return {
|
|
520
525
|
type: "steps-found",
|
|
521
526
|
ctx: this.fnArg,
|
|
522
527
|
ops: this.ops,
|
|
523
|
-
steps:
|
|
528
|
+
steps: allSteps
|
|
524
529
|
};
|
|
525
530
|
};
|
|
526
531
|
const attemptCheckpointAndResume = async (stepResult, resume = true, force = false) => {
|
|
@@ -666,23 +671,36 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
666
671
|
sseResponse = extractSseResponse(data, body);
|
|
667
672
|
resultData = body;
|
|
668
673
|
} else sseResponse = defaultSseResponse(resultData);
|
|
669
|
-
const
|
|
670
|
-
if (
|
|
674
|
+
const newSteps = await this.filterNewSteps(Array.from(this.state.steps.values()));
|
|
675
|
+
if (newSteps?.length) return this.attachLazyOps({
|
|
676
|
+
type: "steps-found",
|
|
677
|
+
ctx: this.fnArg,
|
|
678
|
+
ops: this.ops,
|
|
679
|
+
steps: newSteps
|
|
680
|
+
});
|
|
671
681
|
await this.streamCloseSucceeded(sseResponse);
|
|
672
682
|
if (!this.streamTools.activated) this.postCheckpointStream();
|
|
673
683
|
if (this.options.createResponse) data = await this.options.createResponse(jsonResponse(resultData));
|
|
674
|
-
return this.transformOutput({ data });
|
|
684
|
+
return this.attachLazyOps(this.transformOutput({ data }));
|
|
675
685
|
},
|
|
676
686
|
"function-rejected": async (checkpoint) => {
|
|
677
687
|
if (!this.retriability(checkpoint.error)) await this.streamCloseFailed(errorMessage(checkpoint.error));
|
|
678
688
|
else await this.streamEnd();
|
|
679
689
|
if (!this.streamTools.activated) this.postCheckpointStream();
|
|
680
|
-
return this.transformOutput({ error: checkpoint.error });
|
|
690
|
+
return this.attachLazyOps(this.transformOutput({ error: checkpoint.error }));
|
|
681
691
|
},
|
|
682
692
|
"steps-found": async ({ steps }) => {
|
|
683
693
|
const stepResult = await this.tryExecuteStep(steps);
|
|
684
|
-
if (stepResult) return
|
|
685
|
-
return
|
|
694
|
+
if (!stepResult) return maybeReturnNewSteps();
|
|
695
|
+
if (this.state.lazyOps.length === 0) return stepRanHandler(stepResult);
|
|
696
|
+
const transformed = await stepRanHandler(stepResult);
|
|
697
|
+
if (transformed.type !== "step-ran") return transformed;
|
|
698
|
+
return this.attachLazyOps({
|
|
699
|
+
type: "steps-found",
|
|
700
|
+
ctx: transformed.ctx,
|
|
701
|
+
ops: transformed.ops,
|
|
702
|
+
steps: [transformed.step]
|
|
703
|
+
});
|
|
686
704
|
},
|
|
687
705
|
"step-not-found": ({ step }) => {
|
|
688
706
|
const { foundSteps, totalFoundSteps } = this.getStepNotFoundDetails();
|
|
@@ -705,13 +723,18 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
705
723
|
const asyncCheckpointingHandlers = {
|
|
706
724
|
"": commonCheckpointHandler,
|
|
707
725
|
"function-resolved": async (checkpoint, i) => {
|
|
726
|
+
const lazyOps = this.state.lazyOps.drain();
|
|
708
727
|
const output = await asyncHandlers["function-resolved"](checkpoint, i);
|
|
709
728
|
if (output?.type === "function-resolved") {
|
|
710
|
-
const steps =
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
729
|
+
const steps = [
|
|
730
|
+
...this.state.checkpointingStepBuffer,
|
|
731
|
+
...lazyOps,
|
|
732
|
+
{
|
|
733
|
+
op: StepOpCode.RunComplete,
|
|
734
|
+
id: hashId(RUN_COMPLETE_STEP_ID),
|
|
735
|
+
data: output.data
|
|
736
|
+
}
|
|
737
|
+
];
|
|
715
738
|
if (isNonEmpty(steps)) return {
|
|
716
739
|
type: "steps-found",
|
|
717
740
|
ctx: output.ctx,
|
|
@@ -719,9 +742,14 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
719
742
|
steps
|
|
720
743
|
};
|
|
721
744
|
}
|
|
745
|
+
if (output?.type === "steps-found" && lazyOps.length) return {
|
|
746
|
+
...output,
|
|
747
|
+
steps: [...output.steps, ...lazyOps]
|
|
748
|
+
};
|
|
749
|
+
return output;
|
|
722
750
|
},
|
|
723
751
|
"function-rejected": async (checkpoint) => {
|
|
724
|
-
if (this.state.checkpointingStepBuffer.length) {
|
|
752
|
+
if (this.state.checkpointingStepBuffer.length || this.state.lazyOps.length > 0) {
|
|
725
753
|
const fallback = await attemptCheckpointAndResume(void 0, false, true);
|
|
726
754
|
if (fallback) return fallback;
|
|
727
755
|
}
|
|
@@ -966,7 +994,11 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
966
994
|
* Validate event data against schemas defined in function triggers.
|
|
967
995
|
*/
|
|
968
996
|
async validateEventSchemas() {
|
|
969
|
-
if (this.options.
|
|
997
|
+
if (this.options.handlerKind === "failure") return;
|
|
998
|
+
if (this.options.handlerKind === "defer") {
|
|
999
|
+
await this.validateDeferEventSchema();
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
970
1002
|
const triggers = this.options.fn.opts.triggers;
|
|
971
1003
|
if (!triggers || triggers.length === 0) return;
|
|
972
1004
|
const fnArgEvents = this.fnArg.events;
|
|
@@ -977,6 +1009,17 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
977
1009
|
})), triggers);
|
|
978
1010
|
}
|
|
979
1011
|
/**
|
|
1012
|
+
* Validate the deferred event's data against the defer function's own
|
|
1013
|
+
* schema (set via `createDefer`'s `opts.schema`).
|
|
1014
|
+
*/
|
|
1015
|
+
async validateDeferEventSchema() {
|
|
1016
|
+
const fn = this.options.fn;
|
|
1017
|
+
if (!isDeferredFunction(fn) || !fn.schema) return;
|
|
1018
|
+
const eventData = this.fnArg.event?.data;
|
|
1019
|
+
const result = await fn.schema["~standard"].validate(eventData);
|
|
1020
|
+
if (result.issues) throw new NonRetriableError(`defer handler "${fn.id(this.options.client.id)}" schema validation failed: ${JSON.stringify(result.issues)}`);
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
980
1023
|
* Using middleware, transform output before returning.
|
|
981
1024
|
*/
|
|
982
1025
|
transformOutput(dataOrError) {
|
|
@@ -999,6 +1042,64 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
999
1042
|
data: undefinedToNull(data)
|
|
1000
1043
|
};
|
|
1001
1044
|
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Drain buffered lazy ops (e.g. `DeferAdd` from `defer()`) and merge them
|
|
1047
|
+
* into `result` so they ship in the same outbound message. Lazy ops are
|
|
1048
|
+
* fire-and-forget and have no natural shipping moment, so each terminal code
|
|
1049
|
+
* path must ship them or they're silently dropped.
|
|
1050
|
+
*/
|
|
1051
|
+
attachLazyOps(result, extras = []) {
|
|
1052
|
+
const lazyOps = this.state.lazyOps.drain();
|
|
1053
|
+
if (lazyOps.length === 0 && extras.length === 0) return result;
|
|
1054
|
+
switch (result.type) {
|
|
1055
|
+
case "function-resolved": {
|
|
1056
|
+
const steps = [
|
|
1057
|
+
...extras,
|
|
1058
|
+
...lazyOps,
|
|
1059
|
+
{
|
|
1060
|
+
op: StepOpCode.RunComplete,
|
|
1061
|
+
id: hashId(RUN_COMPLETE_STEP_ID),
|
|
1062
|
+
data: undefinedToNull(result.data)
|
|
1063
|
+
}
|
|
1064
|
+
];
|
|
1065
|
+
return {
|
|
1066
|
+
type: "steps-found",
|
|
1067
|
+
ctx: result.ctx,
|
|
1068
|
+
ops: result.ops,
|
|
1069
|
+
steps
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
case "function-rejected": {
|
|
1073
|
+
const isFinal = result.retriable === false;
|
|
1074
|
+
const steps = [
|
|
1075
|
+
...extras,
|
|
1076
|
+
...lazyOps,
|
|
1077
|
+
{
|
|
1078
|
+
op: isFinal ? StepOpCode.StepFailed : StepOpCode.StepError,
|
|
1079
|
+
id: hashId(RUN_COMPLETE_STEP_ID),
|
|
1080
|
+
error: result.error
|
|
1081
|
+
}
|
|
1082
|
+
];
|
|
1083
|
+
return {
|
|
1084
|
+
type: "steps-found",
|
|
1085
|
+
ctx: result.ctx,
|
|
1086
|
+
ops: result.ops,
|
|
1087
|
+
steps
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
case "steps-found": return {
|
|
1091
|
+
...result,
|
|
1092
|
+
steps: [
|
|
1093
|
+
...result.steps,
|
|
1094
|
+
...extras,
|
|
1095
|
+
...lazyOps
|
|
1096
|
+
]
|
|
1097
|
+
};
|
|
1098
|
+
default:
|
|
1099
|
+
for (const op of lazyOps) this.state.lazyOps.push(op);
|
|
1100
|
+
return result;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1002
1103
|
createExecutionState() {
|
|
1003
1104
|
const d = createDeferredPromiseWithStack();
|
|
1004
1105
|
let checkpointResolve = d.deferred.resolve;
|
|
@@ -1021,6 +1122,7 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
1021
1122
|
const stepsToFulfill = Object.keys(this.options.stepState).length;
|
|
1022
1123
|
return {
|
|
1023
1124
|
stepState: this.options.stepState,
|
|
1125
|
+
priorDefers: this.options.priorDefers ?? {},
|
|
1024
1126
|
stepsToFulfill,
|
|
1025
1127
|
steps: /* @__PURE__ */ new Map(),
|
|
1026
1128
|
loop,
|
|
@@ -1035,6 +1137,7 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
1035
1137
|
return this.state.remainingStepsToBeSeen.size === 0;
|
|
1036
1138
|
},
|
|
1037
1139
|
checkpointingStepBuffer: [],
|
|
1140
|
+
lazyOps: new LazyOps(),
|
|
1038
1141
|
metadata: /* @__PURE__ */ new Map()
|
|
1039
1142
|
};
|
|
1040
1143
|
}
|
|
@@ -1042,17 +1145,22 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
1042
1145
|
return Object.fromEntries(this.state.steps);
|
|
1043
1146
|
}
|
|
1044
1147
|
createFnArg() {
|
|
1045
|
-
const step = this.createStepTools();
|
|
1148
|
+
const { step, defer } = this.createStepTools();
|
|
1046
1149
|
const experimentStepRun = step[experimentStepRunSymbol];
|
|
1047
1150
|
let fnArg = {
|
|
1048
1151
|
...this.options.data,
|
|
1049
1152
|
step,
|
|
1050
|
-
group: createGroupTools({ experimentStepRun })
|
|
1153
|
+
group: createGroupTools({ experimentStepRun }),
|
|
1154
|
+
defer
|
|
1051
1155
|
};
|
|
1156
|
+
if (this.options.handlerKind === "defer") {
|
|
1157
|
+
delete fnArg.event.data._inngest;
|
|
1158
|
+
for (const event of fnArg.events) delete event.data._inngest;
|
|
1159
|
+
}
|
|
1052
1160
|
/**
|
|
1053
1161
|
* Handle use of the `onFailure` option by deserializing the error.
|
|
1054
1162
|
*/
|
|
1055
|
-
if (this.options.
|
|
1163
|
+
if (this.options.handlerKind === "failure") {
|
|
1056
1164
|
const eventData = z.object({ error: jsonErrorSchema }).parse(fnArg.event?.data);
|
|
1057
1165
|
fnArg = {
|
|
1058
1166
|
...fnArg,
|
|
@@ -1181,6 +1289,30 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
1181
1289
|
};
|
|
1182
1290
|
const stepHandler = async ({ args, matchOp, opts }) => {
|
|
1183
1291
|
const opId = matchOp(getStepOptions(args[0]), ...args.slice(1));
|
|
1292
|
+
if (isLazyOp(opts, opId)) {
|
|
1293
|
+
const hashedId$1 = _internals.hashId(opId.id);
|
|
1294
|
+
if (this.state.lazyOps.hasId(hashedId$1)) {
|
|
1295
|
+
this.options.client[internalLoggerSymbol].warn({
|
|
1296
|
+
runId: this.fnArg.runId,
|
|
1297
|
+
id: opId.userland?.id ?? opId.id
|
|
1298
|
+
}, "defer skipped: duplicate ID within run");
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
if (this.state.priorDefers[hashedId$1]) {
|
|
1302
|
+
this.state.lazyOps.markSeen(hashedId$1);
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
this.state.lazyOps.push({
|
|
1306
|
+
id: hashedId$1,
|
|
1307
|
+
op: opId.op,
|
|
1308
|
+
name: opId.name,
|
|
1309
|
+
displayName: opId.displayName ?? opId.id,
|
|
1310
|
+
opts: opId.opts,
|
|
1311
|
+
userland: opId.userland,
|
|
1312
|
+
data: null
|
|
1313
|
+
});
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1184
1316
|
if (this.state.executingStep)
|
|
1185
1317
|
/**
|
|
1186
1318
|
* If a step is found after asynchronous actions during another step's
|
|
@@ -1302,7 +1434,75 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
1302
1434
|
} else pushStepToReport(step);
|
|
1303
1435
|
return promise;
|
|
1304
1436
|
};
|
|
1305
|
-
return
|
|
1437
|
+
return {
|
|
1438
|
+
step: createStepTools(this.options.client, this, stepHandler),
|
|
1439
|
+
defer: this.buildDefer(stepHandler)
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Build the `defer(idOrOptions, { function, data })` method exposed on
|
|
1444
|
+
* every handler context. Validates `data` against the target function's
|
|
1445
|
+
* schema (if any) and emits a `DeferAdd` opcode that routes to the
|
|
1446
|
+
* target's companion function slug.
|
|
1447
|
+
*
|
|
1448
|
+
* `defer()` is fire-and-forget: a misuse should not derail the user's
|
|
1449
|
+
* handler. Validation failures (wrong function, async schema validator,
|
|
1450
|
+
* schema mismatch) are logged and the call is silently skipped.
|
|
1451
|
+
*/
|
|
1452
|
+
buildDefer(stepHandler) {
|
|
1453
|
+
return (idOrOptions, { function: deferFn, data }) => {
|
|
1454
|
+
const log = this.options.client[internalLoggerSymbol];
|
|
1455
|
+
const runId = this.fnArg.runId;
|
|
1456
|
+
try {
|
|
1457
|
+
if (!isDeferredFunction(deferFn)) {
|
|
1458
|
+
log.error({ runId }, "defer skipped: function not created via createDefer");
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
const { schema } = deferFn;
|
|
1462
|
+
const deferFnSlug = deferFn.id(this.options.client.id);
|
|
1463
|
+
let input = data;
|
|
1464
|
+
if (schema) {
|
|
1465
|
+
const result = schema["~standard"].validate(data);
|
|
1466
|
+
if (result instanceof Promise) {
|
|
1467
|
+
log.error({ runId }, "defer() requires a synchronous schema validator. The defer call was skipped.");
|
|
1468
|
+
return;
|
|
1469
|
+
}
|
|
1470
|
+
if (result.issues) {
|
|
1471
|
+
log.error({
|
|
1472
|
+
runId,
|
|
1473
|
+
issues: result.issues
|
|
1474
|
+
}, "defer skipped: schema validation failed");
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
input = result.value ?? data;
|
|
1478
|
+
}
|
|
1479
|
+
stepHandler({
|
|
1480
|
+
args: [idOrOptions, input],
|
|
1481
|
+
matchOp: (stepOptions, inputArg) => ({
|
|
1482
|
+
id: stepOptions.id,
|
|
1483
|
+
mode: StepMode.Sync,
|
|
1484
|
+
op: StepOpCode.DeferAdd,
|
|
1485
|
+
name: stepOptions.name ?? stepOptions.id,
|
|
1486
|
+
displayName: stepOptions.name ?? stepOptions.id,
|
|
1487
|
+
opts: {
|
|
1488
|
+
fn_slug: deferFnSlug,
|
|
1489
|
+
input: inputArg
|
|
1490
|
+
},
|
|
1491
|
+
userland: { id: stepOptions.id }
|
|
1492
|
+
})
|
|
1493
|
+
}).catch((err) => {
|
|
1494
|
+
log.error({
|
|
1495
|
+
runId,
|
|
1496
|
+
err
|
|
1497
|
+
}, "defer skipped: unexpected error");
|
|
1498
|
+
});
|
|
1499
|
+
} catch (err) {
|
|
1500
|
+
log.error({
|
|
1501
|
+
runId,
|
|
1502
|
+
err
|
|
1503
|
+
}, "defer skipped: unexpected error");
|
|
1504
|
+
}
|
|
1505
|
+
};
|
|
1306
1506
|
}
|
|
1307
1507
|
/**
|
|
1308
1508
|
* Applies middleware transformations to a step, resolves ID collisions,
|
|
@@ -1384,14 +1584,19 @@ var InngestExecutionEngine = class extends InngestExecution {
|
|
|
1384
1584
|
return userlandStep;
|
|
1385
1585
|
}
|
|
1386
1586
|
getUserFnToRun() {
|
|
1387
|
-
|
|
1388
|
-
|
|
1587
|
+
switch (this.options.handlerKind) {
|
|
1588
|
+
case "defer": return this.options.fn["fn"];
|
|
1589
|
+
case "failure":
|
|
1590
|
+
if (!this.options.fn["onFailureFn"])
|
|
1389
1591
|
/**
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1592
|
+
* Somehow, we've ended up detecting that this is a failure handler
|
|
1593
|
+
* but doesn't have an `onFailure` function. This should never
|
|
1594
|
+
* happen.
|
|
1595
|
+
*/
|
|
1596
|
+
throw new Error("Cannot find function `onFailure` handler");
|
|
1597
|
+
return this.options.fn["onFailureFn"];
|
|
1598
|
+
default: return this.options.fn["fn"];
|
|
1599
|
+
}
|
|
1395
1600
|
}
|
|
1396
1601
|
initializeTimer(state) {
|
|
1397
1602
|
if (!this.options.requestedRunStep) return;
|