@blokjs/runner 0.2.1 → 0.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/dist/Blok.js +11 -11
- package/dist/Blok.js.map +1 -1
- package/dist/Configuration.d.ts +39 -2
- package/dist/Configuration.js +337 -28
- package/dist/Configuration.js.map +1 -1
- package/dist/ConfigurationResolver.d.ts +9 -0
- package/dist/ConfigurationResolver.js +17 -1
- package/dist/ConfigurationResolver.js.map +1 -1
- package/dist/PayloadTooLargeError.d.ts +19 -0
- package/dist/PayloadTooLargeError.js +29 -0
- package/dist/PayloadTooLargeError.js.map +1 -0
- package/dist/RunCancelledError.d.ts +17 -0
- package/dist/RunCancelledError.js +25 -0
- package/dist/RunCancelledError.js.map +1 -0
- package/dist/RunnerSteps.js +363 -23
- package/dist/RunnerSteps.js.map +1 -1
- package/dist/RuntimeAdapterNode.d.ts +32 -2
- package/dist/RuntimeAdapterNode.js +122 -27
- package/dist/RuntimeAdapterNode.js.map +1 -1
- package/dist/SubworkflowNode.d.ts +75 -0
- package/dist/SubworkflowNode.js +221 -0
- package/dist/SubworkflowNode.js.map +1 -0
- package/dist/TriggerBase.d.ts +128 -0
- package/dist/TriggerBase.js +808 -6
- package/dist/TriggerBase.js.map +1 -1
- package/dist/WaitDispatchRequest.d.ts +38 -0
- package/dist/WaitDispatchRequest.js +13 -0
- package/dist/WaitDispatchRequest.js.map +1 -0
- package/dist/WaitNode.d.ts +23 -0
- package/dist/WaitNode.js +26 -0
- package/dist/WaitNode.js.map +1 -0
- package/dist/adapters/BunRuntimeAdapter.d.ts +1 -0
- package/dist/adapters/BunRuntimeAdapter.js +1 -0
- package/dist/adapters/BunRuntimeAdapter.js.map +1 -1
- package/dist/adapters/DockerRuntimeAdapter.d.ts +2 -1
- package/dist/adapters/DockerRuntimeAdapter.js +10 -1
- package/dist/adapters/DockerRuntimeAdapter.js.map +1 -1
- package/dist/adapters/HttpRuntimeAdapter.d.ts +26 -5
- package/dist/adapters/HttpRuntimeAdapter.js +97 -16
- package/dist/adapters/HttpRuntimeAdapter.js.map +1 -1
- package/dist/adapters/NodeJsRuntimeAdapter.d.ts +1 -0
- package/dist/adapters/NodeJsRuntimeAdapter.js +1 -0
- package/dist/adapters/NodeJsRuntimeAdapter.js.map +1 -1
- package/dist/adapters/RuntimeAdapter.d.ts +17 -0
- package/dist/adapters/WasmRuntimeAdapter.d.ts +1 -0
- package/dist/adapters/WasmRuntimeAdapter.js +1 -0
- package/dist/adapters/WasmRuntimeAdapter.js.map +1 -1
- package/dist/adapters/grpc/GrpcChannelOptions.d.ts +31 -0
- package/dist/adapters/grpc/GrpcChannelOptions.js +68 -0
- package/dist/adapters/grpc/GrpcChannelOptions.js.map +1 -0
- package/dist/adapters/grpc/GrpcClientPool.d.ts +43 -0
- package/dist/adapters/grpc/GrpcClientPool.js +89 -0
- package/dist/adapters/grpc/GrpcClientPool.js.map +1 -0
- package/dist/adapters/grpc/GrpcCodec.d.ts +226 -0
- package/dist/adapters/grpc/GrpcCodec.js +275 -0
- package/dist/adapters/grpc/GrpcCodec.js.map +1 -0
- package/dist/adapters/grpc/GrpcErrors.d.ts +59 -0
- package/dist/adapters/grpc/GrpcErrors.js +190 -0
- package/dist/adapters/grpc/GrpcErrors.js.map +1 -0
- package/dist/adapters/grpc/GrpcHealthChecker.d.ts +69 -0
- package/dist/adapters/grpc/GrpcHealthChecker.js +96 -0
- package/dist/adapters/grpc/GrpcHealthChecker.js.map +1 -0
- package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +98 -0
- package/dist/adapters/grpc/GrpcRuntimeAdapter.js +478 -0
- package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -0
- package/dist/adapters/grpc/index.d.ts +13 -0
- package/dist/adapters/grpc/index.js +14 -0
- package/dist/adapters/grpc/index.js.map +1 -0
- package/dist/adapters/grpc/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/adapters/grpc/types.d.ts +97 -0
- package/dist/adapters/grpc/types.js +41 -0
- package/dist/adapters/grpc/types.js.map +1 -0
- package/dist/adapters/transport.d.ts +108 -0
- package/dist/adapters/transport.js +196 -0
- package/dist/adapters/transport.js.map +1 -0
- package/dist/concurrency/ConcurrencyBackend.d.ts +61 -0
- package/dist/concurrency/ConcurrencyBackend.js +20 -0
- package/dist/concurrency/ConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/ConcurrencyLimitError.d.ts +37 -0
- package/dist/concurrency/ConcurrencyLimitError.js +16 -0
- package/dist/concurrency/ConcurrencyLimitError.js.map +1 -0
- package/dist/concurrency/NatsKvConcurrencyBackend.d.ts +64 -0
- package/dist/concurrency/NatsKvConcurrencyBackend.js +297 -0
- package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/QueueExpiredError.d.ts +40 -0
- package/dist/concurrency/QueueExpiredError.js +15 -0
- package/dist/concurrency/QueueExpiredError.js.map +1 -0
- package/dist/concurrency/createConcurrencyBackend.d.ts +23 -0
- package/dist/concurrency/createConcurrencyBackend.js +34 -0
- package/dist/concurrency/createConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/readConcurrencyConfig.d.ts +60 -0
- package/dist/concurrency/readConcurrencyConfig.js +60 -0
- package/dist/concurrency/readConcurrencyConfig.js.map +1 -0
- package/dist/idempotency/resolveIdempotencyKey.d.ts +20 -0
- package/dist/idempotency/resolveIdempotencyKey.js +37 -0
- package/dist/idempotency/resolveIdempotencyKey.js.map +1 -0
- package/dist/index.d.ts +35 -3
- package/dist/index.js +61 -2
- package/dist/index.js.map +1 -1
- package/dist/monitoring/ConcurrencyMetrics.d.ts +56 -0
- package/dist/monitoring/ConcurrencyMetrics.js +107 -0
- package/dist/monitoring/ConcurrencyMetrics.js.map +1 -0
- package/dist/monitoring/JanitorMetrics.d.ts +27 -0
- package/dist/monitoring/JanitorMetrics.js +48 -0
- package/dist/monitoring/JanitorMetrics.js.map +1 -0
- package/dist/scheduling/DebounceCoordinator.d.ts +88 -0
- package/dist/scheduling/DebounceCoordinator.js +141 -0
- package/dist/scheduling/DebounceCoordinator.js.map +1 -0
- package/dist/scheduling/DeferredDispatchSignal.d.ts +50 -0
- package/dist/scheduling/DeferredDispatchSignal.js +14 -0
- package/dist/scheduling/DeferredDispatchSignal.js.map +1 -0
- package/dist/scheduling/DeferredRunScheduler.d.ts +68 -0
- package/dist/scheduling/DeferredRunScheduler.js +154 -0
- package/dist/scheduling/DeferredRunScheduler.js.map +1 -0
- package/dist/scheduling/readSchedulingConfig.d.ts +24 -0
- package/dist/scheduling/readSchedulingConfig.js +52 -0
- package/dist/scheduling/readSchedulingConfig.js.map +1 -0
- package/dist/testing/WorkflowTestRunner.js +12 -0
- package/dist/testing/WorkflowTestRunner.js.map +1 -1
- package/dist/timeouts/StepTimeoutError.d.ts +22 -0
- package/dist/timeouts/StepTimeoutError.js +31 -0
- package/dist/timeouts/StepTimeoutError.js.map +1 -0
- package/dist/tracing/InMemoryRunStore.d.ts +28 -1
- package/dist/tracing/InMemoryRunStore.js +150 -0
- package/dist/tracing/InMemoryRunStore.js.map +1 -1
- package/dist/tracing/Janitor.d.ts +70 -0
- package/dist/tracing/Janitor.js +150 -0
- package/dist/tracing/Janitor.js.map +1 -0
- package/dist/tracing/PostgresRunStore.d.ts +30 -0
- package/dist/tracing/PostgresRunStore.js +435 -3
- package/dist/tracing/PostgresRunStore.js.map +1 -1
- package/dist/tracing/RunStore.d.ts +100 -1
- package/dist/tracing/RunTracker.d.ts +261 -11
- package/dist/tracing/RunTracker.js +691 -11
- package/dist/tracing/RunTracker.js.map +1 -1
- package/dist/tracing/SqliteRunStore.d.ts +23 -1
- package/dist/tracing/SqliteRunStore.js +421 -6
- package/dist/tracing/SqliteRunStore.js.map +1 -1
- package/dist/tracing/TraceRouter.d.ts +20 -2
- package/dist/tracing/TraceRouter.js +494 -9
- package/dist/tracing/TraceRouter.js.map +1 -1
- package/dist/tracing/sanitize.d.ts +11 -0
- package/dist/tracing/sanitize.js +29 -0
- package/dist/tracing/sanitize.js.map +1 -1
- package/dist/tracing/types.d.ts +429 -11
- package/dist/types/GlobalOptions.d.ts +9 -2
- package/dist/utils/createChildContext.d.ts +32 -0
- package/dist/utils/createChildContext.js +113 -0
- package/dist/utils/createChildContext.js.map +1 -0
- package/dist/workflow/PersistenceHelper.d.ts +46 -0
- package/dist/workflow/PersistenceHelper.js +57 -0
- package/dist/workflow/PersistenceHelper.js.map +1 -0
- package/dist/workflow/WorkflowNormalizer.d.ts +79 -0
- package/dist/workflow/WorkflowNormalizer.js +486 -0
- package/dist/workflow/WorkflowNormalizer.js.map +1 -0
- package/dist/workflow/WorkflowRegistry.d.ts +64 -0
- package/dist/workflow/WorkflowRegistry.js +81 -0
- package/dist/workflow/WorkflowRegistry.js.map +1 -0
- package/package.json +10 -7
|
@@ -11,9 +11,39 @@ import type { RuntimeAdapter } from "./adapters/RuntimeAdapter";
|
|
|
11
11
|
export declare class RuntimeAdapterNode extends RunnerNode {
|
|
12
12
|
private adapter;
|
|
13
13
|
private targetNode;
|
|
14
|
-
|
|
14
|
+
private streamLogs;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Wire transport this node uses (`http` | `grpc` | `module`). Surfaced
|
|
17
|
+
* in the step-prefix log by `RunnerSteps` so operators can tell at a
|
|
18
|
+
* glance which path a runtime node took during the migration. Read-only;
|
|
19
|
+
* mirrors the underlying adapter's `transport` field.
|
|
20
|
+
*/
|
|
21
|
+
readonly transport: RuntimeAdapter["transport"];
|
|
22
|
+
constructor(adapter: RuntimeAdapter, targetNode: RunnerNode, opts?: {
|
|
23
|
+
streamLogs?: boolean;
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Execute the node using the runtime adapter.
|
|
27
|
+
*
|
|
28
|
+
* When `streamLogs=true` AND the adapter exposes `executeStream`, routes
|
|
29
|
+
* through the server-streaming path so node-emitted `LogLine` events flow
|
|
30
|
+
* into the tracker (and thus into Studio's SSE stream) live. Falls back
|
|
31
|
+
* to unary `execute` when streaming isn't enabled or isn't supported by
|
|
32
|
+
* this adapter (e.g. HttpRuntimeAdapter has no streaming surface).
|
|
17
33
|
*/
|
|
18
34
|
run(ctx: Context): Promise<ResponseContext>;
|
|
35
|
+
/**
|
|
36
|
+
* True when streaming is enabled for this node AND the adapter exposes a
|
|
37
|
+
* server-streaming `executeStream` method. The shape check is
|
|
38
|
+
* intentionally duck-typed so any future adapter that implements
|
|
39
|
+
* streaming Just Works without coupling this class to GrpcRuntimeAdapter.
|
|
40
|
+
*/
|
|
41
|
+
private canStream;
|
|
42
|
+
/**
|
|
43
|
+
* Run the node via the adapter's streaming surface, draining log frames
|
|
44
|
+
* into `RunTracker.addLog` as they arrive. Returns the same
|
|
45
|
+
* `ExecutionResult` shape as the unary path so callers handle both flows
|
|
46
|
+
* identically.
|
|
47
|
+
*/
|
|
48
|
+
private runStreaming;
|
|
19
49
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { GlobalError } from "@blokjs/shared";
|
|
2
2
|
import RunnerNode from "./RunnerNode";
|
|
3
3
|
import { RunTracker } from "./tracing/RunTracker";
|
|
4
|
+
import { applyStepOutput } from "./workflow/PersistenceHelper";
|
|
4
5
|
/**
|
|
5
6
|
* RuntimeAdapterNode is a wrapper that bridges the existing RunnerNode interface
|
|
6
7
|
* with the new RuntimeAdapter system.
|
|
@@ -11,10 +12,20 @@ import { RunTracker } from "./tracing/RunTracker";
|
|
|
11
12
|
export class RuntimeAdapterNode extends RunnerNode {
|
|
12
13
|
adapter;
|
|
13
14
|
targetNode;
|
|
14
|
-
|
|
15
|
+
streamLogs;
|
|
16
|
+
/**
|
|
17
|
+
* Wire transport this node uses (`http` | `grpc` | `module`). Surfaced
|
|
18
|
+
* in the step-prefix log by `RunnerSteps` so operators can tell at a
|
|
19
|
+
* glance which path a runtime node took during the migration. Read-only;
|
|
20
|
+
* mirrors the underlying adapter's `transport` field.
|
|
21
|
+
*/
|
|
22
|
+
transport;
|
|
23
|
+
constructor(adapter, targetNode, opts = {}) {
|
|
15
24
|
super();
|
|
16
25
|
this.adapter = adapter;
|
|
17
26
|
this.targetNode = targetNode;
|
|
27
|
+
this.streamLogs = opts.streamLogs === true;
|
|
28
|
+
this.transport = adapter.transport;
|
|
18
29
|
// Copy properties from target node
|
|
19
30
|
this.node = targetNode.node;
|
|
20
31
|
this.name = targetNode.name;
|
|
@@ -23,41 +34,57 @@ export class RuntimeAdapterNode extends RunnerNode {
|
|
|
23
34
|
this.active = targetNode.active;
|
|
24
35
|
this.stop = targetNode.stop;
|
|
25
36
|
this.set_var = targetNode.set_var;
|
|
37
|
+
// V2 persistence knobs — flow through to PersistenceHelper.
|
|
38
|
+
this.as = targetNode.as;
|
|
39
|
+
this.spread = targetNode.spread;
|
|
40
|
+
this.ephemeral = targetNode.ephemeral;
|
|
26
41
|
}
|
|
27
42
|
/**
|
|
28
|
-
* Execute the node using the runtime adapter
|
|
43
|
+
* Execute the node using the runtime adapter.
|
|
44
|
+
*
|
|
45
|
+
* When `streamLogs=true` AND the adapter exposes `executeStream`, routes
|
|
46
|
+
* through the server-streaming path so node-emitted `LogLine` events flow
|
|
47
|
+
* into the tracker (and thus into Studio's SSE stream) live. Falls back
|
|
48
|
+
* to unary `execute` when streaming isn't enabled or isn't supported by
|
|
49
|
+
* this adapter (e.g. HttpRuntimeAdapter has no streaming surface).
|
|
29
50
|
*/
|
|
30
51
|
async run(ctx) {
|
|
31
|
-
const
|
|
32
|
-
// --- Trace: capture runtime metrics ---
|
|
52
|
+
const traceRunId = ctx._traceRunId;
|
|
33
53
|
const traceNodeId = ctx._traceNodeId;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
54
|
+
const tracker = traceRunId ? RunTracker.getInstance() : null;
|
|
55
|
+
const result = this.canStream()
|
|
56
|
+
? await this.runStreaming(ctx, tracker, traceRunId, traceNodeId)
|
|
57
|
+
: await this.adapter.execute(this.targetNode, ctx);
|
|
58
|
+
// --- Trace: stash runtime metrics on ctx so RunnerSteps can pass
|
|
59
|
+
// them to `tracker.completeNode(...)` as the third argument. The
|
|
60
|
+
// previous in-place mutation via `tracker.getNodeRun()` was a
|
|
61
|
+
// dead-end: SqliteRunStore.getNodeRun reconstructs from a row, so
|
|
62
|
+
// the mutation landed on a detached object; even on InMemoryRunStore
|
|
63
|
+
// the next `completeNode(nodeRunId, outputs)` call wrote
|
|
64
|
+
// `metrics: undefined` over it. Stashing on ctx and threading
|
|
65
|
+
// through `completeNode` is the single path that survives all
|
|
66
|
+
// store implementations and the NODE_COMPLETED event payload.
|
|
67
|
+
if (result.metrics) {
|
|
68
|
+
ctx._stepMetrics = result.metrics;
|
|
45
69
|
}
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
70
|
+
// Defensive: ensure state exists. TriggerBase initializes it, but
|
|
71
|
+
// some legacy code paths construct ctx by hand. ctx.vars and
|
|
72
|
+
// ctx.state alias the same object; we read/write through `state`.
|
|
73
|
+
if (!ctx.state || typeof ctx.state !== "object") {
|
|
74
|
+
ctx.state = {};
|
|
49
75
|
}
|
|
50
|
-
const
|
|
51
|
-
// Merge SDK-returned
|
|
76
|
+
const state = ctx.state;
|
|
77
|
+
// Merge SDK-returned `vars_delta` into state. This is the SDK's
|
|
78
|
+
// explicit publication path (proto field `vars_delta` on
|
|
79
|
+
// ExecuteResponse) — it stacks with the auto-store rule below.
|
|
52
80
|
if (result.vars && typeof result.vars === "object") {
|
|
53
|
-
Object.assign(
|
|
54
|
-
}
|
|
55
|
-
// Auto-save the step's result data into ctx.vars[stepName]
|
|
56
|
-
// This ensures each runtime step's output is accessible downstream,
|
|
57
|
-
// even if the SDK server doesn't explicitly return vars
|
|
58
|
-
if (result.data != null) {
|
|
59
|
-
vars[this.name] = result.data;
|
|
81
|
+
Object.assign(state, result.vars);
|
|
60
82
|
}
|
|
83
|
+
// V2 persistence — runner-owned, declarative.
|
|
84
|
+
// `ephemeral` skips, `spread` merges, `as` renames, default stores
|
|
85
|
+
// at state[name]. SDK nodes have always auto-stored (today's
|
|
86
|
+
// behaviour); this just routes through the unified helper.
|
|
87
|
+
applyStepOutput(ctx, this, result);
|
|
61
88
|
// Convert errors to GlobalError if present
|
|
62
89
|
let error = null;
|
|
63
90
|
if (result.errors) {
|
|
@@ -83,5 +110,73 @@ export class RuntimeAdapterNode extends RunnerNode {
|
|
|
83
110
|
error,
|
|
84
111
|
};
|
|
85
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* True when streaming is enabled for this node AND the adapter exposes a
|
|
115
|
+
* server-streaming `executeStream` method. The shape check is
|
|
116
|
+
* intentionally duck-typed so any future adapter that implements
|
|
117
|
+
* streaming Just Works without coupling this class to GrpcRuntimeAdapter.
|
|
118
|
+
*/
|
|
119
|
+
canStream() {
|
|
120
|
+
if (!this.streamLogs)
|
|
121
|
+
return false;
|
|
122
|
+
const candidate = this.adapter;
|
|
123
|
+
return typeof candidate.executeStream === "function";
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Run the node via the adapter's streaming surface, draining log frames
|
|
127
|
+
* into `RunTracker.addLog` as they arrive. Returns the same
|
|
128
|
+
* `ExecutionResult` shape as the unary path so callers handle both flows
|
|
129
|
+
* identically.
|
|
130
|
+
*/
|
|
131
|
+
async runStreaming(ctx, tracker, traceRunId, traceNodeId) {
|
|
132
|
+
const streamingAdapter = this.adapter;
|
|
133
|
+
const { events, result } = streamingAdapter.executeStream(this.targetNode, ctx);
|
|
134
|
+
for await (const event of events) {
|
|
135
|
+
if (event.type === "log" && tracker && traceRunId) {
|
|
136
|
+
tracker.addLog({
|
|
137
|
+
runId: traceRunId,
|
|
138
|
+
nodeId: traceNodeId,
|
|
139
|
+
nodeName: this.name,
|
|
140
|
+
level: normalizeLogLevel(event.log.level),
|
|
141
|
+
message: event.log.message,
|
|
142
|
+
data: Object.keys(event.log.attributes).length > 0 ? event.log.attributes : undefined,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
else if (event.type === "progress" && tracker && traceNodeId) {
|
|
146
|
+
// Live progress hint — overwrites any previous;
|
|
147
|
+
// emits NODE_PROGRESS for Studio SSE.
|
|
148
|
+
tracker.recordProgress(traceNodeId, event.percent, event.phase);
|
|
149
|
+
}
|
|
150
|
+
else if (event.type === "partial" && tracker && traceNodeId) {
|
|
151
|
+
// Interim snapshot — overwrites any previous;
|
|
152
|
+
// emits NODE_PARTIAL_RESULT for Studio SSE.
|
|
153
|
+
tracker.recordPartialResult(traceNodeId, event.snapshot);
|
|
154
|
+
}
|
|
155
|
+
// `started` is intentionally ignored at this layer — the
|
|
156
|
+
// node lifecycle (NodeStarted / metrics / completion) is
|
|
157
|
+
// already tracked by RunnerSteps via `startNode` /
|
|
158
|
+
// `completeNode`.
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Coerce a wire-side log level string into the runner's 4-tier
|
|
165
|
+
* `TraceLogEntry["level"]`. Defensive against SDK-side variations
|
|
166
|
+
* ("warning" → "warn", "WARN" → "warn", unknown → "info").
|
|
167
|
+
*/
|
|
168
|
+
function normalizeLogLevel(level) {
|
|
169
|
+
const normalized = level.trim().toLowerCase();
|
|
170
|
+
switch (normalized) {
|
|
171
|
+
case "debug":
|
|
172
|
+
case "info":
|
|
173
|
+
case "error":
|
|
174
|
+
return normalized;
|
|
175
|
+
case "warn":
|
|
176
|
+
case "warning":
|
|
177
|
+
return "warn";
|
|
178
|
+
default:
|
|
179
|
+
return "info";
|
|
180
|
+
}
|
|
86
181
|
}
|
|
87
182
|
//# sourceMappingURL=RuntimeAdapterNode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuntimeAdapterNode.js","sourceRoot":"","sources":["../src/RuntimeAdapterNode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,UAAU,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"RuntimeAdapterNode.js","sourceRoot":"","sources":["../src/RuntimeAdapterNode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Context, ResponseContext } from "@blokjs/shared";
|
|
2
|
+
import RunnerNode from "./RunnerNode";
|
|
3
|
+
import type GlobalOptions from "./types/GlobalOptions";
|
|
4
|
+
/**
|
|
5
|
+
* `SubworkflowNode` — the runner-side dispatch primitive that powers
|
|
6
|
+
* the v2 `subworkflow:` step shape. Looks up the named child workflow
|
|
7
|
+
* in the `WorkflowRegistry`, materializes a child `Configuration` +
|
|
8
|
+
* `Runner`, runs the child to completion in its own isolated `Context`,
|
|
9
|
+
* and returns the child's `ctx.response` as this step's `model.data`.
|
|
10
|
+
*
|
|
11
|
+
* **Composition with Tier 1**:
|
|
12
|
+
* - Parent step's `idempotencyKey` is consulted by `RunnerSteps` BEFORE
|
|
13
|
+
* `SubworkflowNode.run` is even called — cache hit short-circuits the
|
|
14
|
+
* entire sub-workflow (no child invocation, no side effects fire).
|
|
15
|
+
* This is the headline pattern AND the documented footgun.
|
|
16
|
+
* - Parent step's `retry` retries the whole sub-workflow on failure;
|
|
17
|
+
* each retry creates a fresh child run record under the same parent.
|
|
18
|
+
* - Replay re-creates fresh sub-run lineage automatically — the new
|
|
19
|
+
* parent run invokes the sub-workflow fresh.
|
|
20
|
+
*
|
|
21
|
+
* **Lineage**: child's `WorkflowRun.parentRunId` and
|
|
22
|
+
* `WorkflowRun.parentNodeRunId` carry the parent run + step that
|
|
23
|
+
* invoked it. Studio renders a "called from #..." breadcrumb on the
|
|
24
|
+
* child and a "Sub-runs" list on the parent.
|
|
25
|
+
*
|
|
26
|
+
* **Recursion guard**: `BLOK_MAX_SUBWORKFLOW_DEPTH` (default 10) bounds
|
|
27
|
+
* cycle / deep-nesting blast radius. Throws a clear error past the cap.
|
|
28
|
+
*/
|
|
29
|
+
export declare class SubworkflowNode extends RunnerNode {
|
|
30
|
+
/**
|
|
31
|
+
* The child workflow's `name:` field — looked up in `WorkflowRegistry`
|
|
32
|
+
* at run time. Set by `Configuration.subworkflowResolver`; this field
|
|
33
|
+
* shadows the inherited `NodeBase.subworkflow` so callers can rely on
|
|
34
|
+
* it being defined.
|
|
35
|
+
*/
|
|
36
|
+
subworkflow: string;
|
|
37
|
+
/**
|
|
38
|
+
* Wait mode for the sub-workflow dispatch:
|
|
39
|
+
*
|
|
40
|
+
* - `true` (default) — synchronous: parent step blocks on the child
|
|
41
|
+
* and the child's `ctx.response` becomes the parent step's output.
|
|
42
|
+
* - `false` — fire-and-forget: parent step returns IMMEDIATELY with
|
|
43
|
+
* `{runId, workflowName, scheduledAt}`. The child runs
|
|
44
|
+
* asynchronously via `setImmediate` and shows up in Studio's
|
|
45
|
+
* Sub-runs strip with status transitioning `running → completed |
|
|
46
|
+
* failed` independently of the parent.
|
|
47
|
+
*
|
|
48
|
+
* Combine `wait: false` with `idempotencyKey` for at-most-once
|
|
49
|
+
* dispatch deduplication (the `runId` is cached against the key
|
|
50
|
+
* regardless of child outcome — Trigger.dev / Stripe semantics).
|
|
51
|
+
*/
|
|
52
|
+
wait: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Runner-wide options (carries the `nodes` registry that the child
|
|
55
|
+
* Configuration needs for `module` step resolution). Set by
|
|
56
|
+
* `Configuration.subworkflowResolver` before this node runs.
|
|
57
|
+
*/
|
|
58
|
+
globalOptions?: GlobalOptions;
|
|
59
|
+
run(ctx: Context): Promise<ResponseContext>;
|
|
60
|
+
/**
|
|
61
|
+
* Fire-and-forget dispatch (Tier 2 #4 follow-up — `wait: false`).
|
|
62
|
+
*
|
|
63
|
+
* Schedules the child runner via `setImmediate` so the parent step
|
|
64
|
+
* can return immediately. Child errors are caught and routed to
|
|
65
|
+
* `tracker.failRun(childRunId, err)` — visible in Studio, NOT
|
|
66
|
+
* propagated to the parent step (which has already returned). Also
|
|
67
|
+
* logged via `console.error` for ops visibility.
|
|
68
|
+
*
|
|
69
|
+
* Parent step's output is the dispatch metadata `{runId,
|
|
70
|
+
* workflowName, scheduledAt}` — NOT the child's response (which
|
|
71
|
+
* doesn't exist yet). Caller polls `GET /__blok/runs/<runId>` for
|
|
72
|
+
* the actual outcome.
|
|
73
|
+
*/
|
|
74
|
+
private dispatchAsync;
|
|
75
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import Configuration from "./Configuration";
|
|
2
|
+
import RunnerNode from "./RunnerNode";
|
|
3
|
+
import { RunTracker } from "./tracing/RunTracker";
|
|
4
|
+
import { createChildContext } from "./utils/createChildContext";
|
|
5
|
+
import { applyStepOutput } from "./workflow/PersistenceHelper";
|
|
6
|
+
import { WorkflowRegistry } from "./workflow/WorkflowRegistry";
|
|
7
|
+
/**
|
|
8
|
+
* Hard cap on `parent → child → grandchild → …` recursion. Bounds the
|
|
9
|
+
* blast radius of an accidental cycle (workflow A calls B calls A) or
|
|
10
|
+
* a legitimate-but-pathological deep nesting. Tunable via
|
|
11
|
+
* `BLOK_MAX_SUBWORKFLOW_DEPTH` env var; falls back to 10.
|
|
12
|
+
*/
|
|
13
|
+
function getMaxDepth() {
|
|
14
|
+
const raw = process.env.BLOK_MAX_SUBWORKFLOW_DEPTH;
|
|
15
|
+
if (typeof raw === "string" && raw.length > 0) {
|
|
16
|
+
const parsed = Number.parseInt(raw, 10);
|
|
17
|
+
if (Number.isInteger(parsed) && parsed > 0)
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
20
|
+
return 10;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Internal ctx field that carries the current sub-workflow depth.
|
|
24
|
+
* Incremented by `SubworkflowNode.run` before invoking the child;
|
|
25
|
+
* read on entry to enforce the cap.
|
|
26
|
+
*/
|
|
27
|
+
const SUBWORKFLOW_DEPTH_KEY = "_subworkflowDepth";
|
|
28
|
+
/**
|
|
29
|
+
* `SubworkflowNode` — the runner-side dispatch primitive that powers
|
|
30
|
+
* the v2 `subworkflow:` step shape. Looks up the named child workflow
|
|
31
|
+
* in the `WorkflowRegistry`, materializes a child `Configuration` +
|
|
32
|
+
* `Runner`, runs the child to completion in its own isolated `Context`,
|
|
33
|
+
* and returns the child's `ctx.response` as this step's `model.data`.
|
|
34
|
+
*
|
|
35
|
+
* **Composition with Tier 1**:
|
|
36
|
+
* - Parent step's `idempotencyKey` is consulted by `RunnerSteps` BEFORE
|
|
37
|
+
* `SubworkflowNode.run` is even called — cache hit short-circuits the
|
|
38
|
+
* entire sub-workflow (no child invocation, no side effects fire).
|
|
39
|
+
* This is the headline pattern AND the documented footgun.
|
|
40
|
+
* - Parent step's `retry` retries the whole sub-workflow on failure;
|
|
41
|
+
* each retry creates a fresh child run record under the same parent.
|
|
42
|
+
* - Replay re-creates fresh sub-run lineage automatically — the new
|
|
43
|
+
* parent run invokes the sub-workflow fresh.
|
|
44
|
+
*
|
|
45
|
+
* **Lineage**: child's `WorkflowRun.parentRunId` and
|
|
46
|
+
* `WorkflowRun.parentNodeRunId` carry the parent run + step that
|
|
47
|
+
* invoked it. Studio renders a "called from #..." breadcrumb on the
|
|
48
|
+
* child and a "Sub-runs" list on the parent.
|
|
49
|
+
*
|
|
50
|
+
* **Recursion guard**: `BLOK_MAX_SUBWORKFLOW_DEPTH` (default 10) bounds
|
|
51
|
+
* cycle / deep-nesting blast radius. Throws a clear error past the cap.
|
|
52
|
+
*/
|
|
53
|
+
export class SubworkflowNode extends RunnerNode {
|
|
54
|
+
/**
|
|
55
|
+
* Runner-wide options (carries the `nodes` registry that the child
|
|
56
|
+
* Configuration needs for `module` step resolution). Set by
|
|
57
|
+
* `Configuration.subworkflowResolver` before this node runs.
|
|
58
|
+
*/
|
|
59
|
+
globalOptions;
|
|
60
|
+
async run(ctx) {
|
|
61
|
+
// === 1. Recursion guard ===
|
|
62
|
+
const depth = (ctx[SUBWORKFLOW_DEPTH_KEY] ?? 0) + 1;
|
|
63
|
+
const maxDepth = getMaxDepth();
|
|
64
|
+
if (depth > maxDepth) {
|
|
65
|
+
throw new Error(`[blok] Sub-workflow recursion limit exceeded (depth ${depth} > ${maxDepth}). Likely a cycle: workflow "${ctx.workflow_name}" called sub-workflow "${this.subworkflow}" too deep. Bump via BLOK_MAX_SUBWORKFLOW_DEPTH if intentional.`);
|
|
66
|
+
}
|
|
67
|
+
// === 2. Look up the child workflow ===
|
|
68
|
+
const registry = WorkflowRegistry.getInstance();
|
|
69
|
+
const entry = registry.get(this.subworkflow);
|
|
70
|
+
if (!entry) {
|
|
71
|
+
const known = registry.list().map((w) => w.name);
|
|
72
|
+
const knownStr = known.length > 0 ? known.join(", ") : "(none registered yet)";
|
|
73
|
+
throw new Error(`[blok] Sub-workflow "${this.subworkflow}" not found in WorkflowRegistry. Available: ${knownStr}. Workflows are registered automatically by the HTTP trigger at boot — make sure the child workflow file is in the scanned directory and has \`name: "${this.subworkflow}"\`.`);
|
|
74
|
+
}
|
|
75
|
+
// === 3. Materialize child Configuration + Runner ===
|
|
76
|
+
// `preloaded` = entry.workflow skips the disk re-read; the
|
|
77
|
+
// normalizer still runs so v1→v2 conversion happens for legacy
|
|
78
|
+
// child workflows.
|
|
79
|
+
const childConfig = new Configuration();
|
|
80
|
+
await childConfig.init(entry.name, this.globalOptions, entry.workflow);
|
|
81
|
+
// Lazy import of Runner to avoid a circular dep
|
|
82
|
+
// (Configuration → RunnerNode → ... — Runner has its own chain).
|
|
83
|
+
const { default: Runner } = await import("./Runner");
|
|
84
|
+
const childRunner = new Runner(childConfig.steps);
|
|
85
|
+
// === 4. Build the child Context ===
|
|
86
|
+
// Parent step's resolved inputs (from blueprint mapper) live on
|
|
87
|
+
// `ctx.config[this.name].inputs` — the blueprint mapper has
|
|
88
|
+
// mutated the wrapper in place, so `js/...` and `$.<path>`
|
|
89
|
+
// expressions are now concrete values. These become the child's
|
|
90
|
+
// `request.body` so the child reads them via `$.req.body.<key>`
|
|
91
|
+
// exactly as if HTTP-triggered (function-call semantics).
|
|
92
|
+
const parentNodeConfig = ctx.config?.[this.name];
|
|
93
|
+
const parentInputs = parentNodeConfig?.inputs ?? {};
|
|
94
|
+
const childCtx = createChildContext(ctx, {
|
|
95
|
+
workflowName: entry.name,
|
|
96
|
+
workflowPath: entry.source,
|
|
97
|
+
body: parentInputs,
|
|
98
|
+
config: childConfig.nodes,
|
|
99
|
+
});
|
|
100
|
+
// Carry the depth counter forward so nested sub-workflows hit the cap.
|
|
101
|
+
childCtx[SUBWORKFLOW_DEPTH_KEY] = depth;
|
|
102
|
+
// === 5. Tracing — child gets its own run record + lineage ===
|
|
103
|
+
const tracker = RunTracker.getInstance();
|
|
104
|
+
const parentRunId = ctx._traceRunId;
|
|
105
|
+
const parentNodeRunId = ctx._traceNodeId;
|
|
106
|
+
const childTriggerSummary = `${ctx.workflow_name ?? "?"} → ${entry.name}`;
|
|
107
|
+
let childRunId;
|
|
108
|
+
if (tracker.active) {
|
|
109
|
+
const childRun = tracker.startRun({
|
|
110
|
+
workflowName: entry.name,
|
|
111
|
+
workflowPath: entry.source,
|
|
112
|
+
triggerType: "subworkflow",
|
|
113
|
+
triggerSummary: childTriggerSummary,
|
|
114
|
+
nodeCount: childConfig.steps.length,
|
|
115
|
+
parentRunId,
|
|
116
|
+
parentNodeRunId,
|
|
117
|
+
});
|
|
118
|
+
childRunId = childRun.id;
|
|
119
|
+
childCtx._traceRunId = childRun.id;
|
|
120
|
+
}
|
|
121
|
+
// === 6. Dispatch — sync or fire-and-forget based on `this.wait` ===
|
|
122
|
+
if (this.wait === false) {
|
|
123
|
+
return this.dispatchAsync(ctx, childRunner, childCtx, childRunId, entry.name);
|
|
124
|
+
}
|
|
125
|
+
// === 6a. Synchronous dispatch (wait: true / default) ===
|
|
126
|
+
try {
|
|
127
|
+
await childRunner.run(childCtx);
|
|
128
|
+
if (childRunId)
|
|
129
|
+
tracker.completeRun(childRunId, childCtx.response);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (childRunId)
|
|
133
|
+
tracker.failRun(childRunId, err);
|
|
134
|
+
throw err;
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
// PR 1 follow-up · A3 fix. Abort the listener-cleanup signal so
|
|
138
|
+
// the parent.signal listener (registered in createChildContext)
|
|
139
|
+
// auto-removes. Without this, listeners accumulate on long-lived
|
|
140
|
+
// parents that fire many sub-workflows.
|
|
141
|
+
const childPrivate = childCtx._PRIVATE_;
|
|
142
|
+
if (childPrivate?.listenerCleanup && !childPrivate.listenerCleanup.signal.aborted) {
|
|
143
|
+
childPrivate.listenerCleanup.abort();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// === 7. Apply parent persistence + return child's response ===
|
|
147
|
+
// Mirrors HTTP function-call semantics: parent reads child output
|
|
148
|
+
// at `$.state[<this.name>]`. Child author controls the shape via
|
|
149
|
+
// `@blokjs/respond` (or the last step's natural output).
|
|
150
|
+
//
|
|
151
|
+
// Persistence-helper call mirrors the RuntimeAdapterNode pattern
|
|
152
|
+
// (RuntimeAdapterNode.ts:100). The parent step's `as` / `spread`
|
|
153
|
+
// / `ephemeral` knobs apply identically here — sub-workflow
|
|
154
|
+
// output is just data, persistence rules are uniform.
|
|
155
|
+
const result = { success: !childCtx.response?.error, data: childCtx.response };
|
|
156
|
+
applyStepOutput(ctx, this, result);
|
|
157
|
+
return {
|
|
158
|
+
success: result.success,
|
|
159
|
+
data: childCtx.response,
|
|
160
|
+
error: childCtx.response?.error ?? null,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Fire-and-forget dispatch (Tier 2 #4 follow-up — `wait: false`).
|
|
165
|
+
*
|
|
166
|
+
* Schedules the child runner via `setImmediate` so the parent step
|
|
167
|
+
* can return immediately. Child errors are caught and routed to
|
|
168
|
+
* `tracker.failRun(childRunId, err)` — visible in Studio, NOT
|
|
169
|
+
* propagated to the parent step (which has already returned). Also
|
|
170
|
+
* logged via `console.error` for ops visibility.
|
|
171
|
+
*
|
|
172
|
+
* Parent step's output is the dispatch metadata `{runId,
|
|
173
|
+
* workflowName, scheduledAt}` — NOT the child's response (which
|
|
174
|
+
* doesn't exist yet). Caller polls `GET /__blok/runs/<runId>` for
|
|
175
|
+
* the actual outcome.
|
|
176
|
+
*/
|
|
177
|
+
dispatchAsync(parentCtx, childRunner, childCtx, childRunId, childWorkflowName) {
|
|
178
|
+
const scheduledAt = Date.now();
|
|
179
|
+
const tracker = RunTracker.getInstance();
|
|
180
|
+
setImmediate(() => {
|
|
181
|
+
void (async () => {
|
|
182
|
+
try {
|
|
183
|
+
await childRunner.run(childCtx);
|
|
184
|
+
if (childRunId)
|
|
185
|
+
tracker.completeRun(childRunId, childCtx.response);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
if (childRunId) {
|
|
189
|
+
tracker.failRun(childRunId, err instanceof Error ? err : new Error(String(err)));
|
|
190
|
+
}
|
|
191
|
+
console.error(`[blok][subworkflow] async child '${childWorkflowName}' (run ${childRunId ?? "?"}) failed:`, err instanceof Error ? err.stack || err.message : err);
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
// PR 1 follow-up · A3 fix. Same listener-cleanup hook as the
|
|
195
|
+
// sync path so async sub-workflows also auto-remove the
|
|
196
|
+
// parent.signal listener on completion.
|
|
197
|
+
const childPrivate = childCtx._PRIVATE_;
|
|
198
|
+
if (childPrivate?.listenerCleanup && !childPrivate.listenerCleanup.signal.aborted) {
|
|
199
|
+
childPrivate.listenerCleanup.abort();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
})();
|
|
203
|
+
});
|
|
204
|
+
// Parent step's output: dispatch metadata (the runId is the
|
|
205
|
+
// canonical handle for at-most-once dispatch deduplication when
|
|
206
|
+
// combined with `idempotencyKey`).
|
|
207
|
+
const dispatchData = {
|
|
208
|
+
runId: childRunId ?? null,
|
|
209
|
+
workflowName: childWorkflowName,
|
|
210
|
+
scheduledAt,
|
|
211
|
+
};
|
|
212
|
+
const result = { success: true, data: dispatchData };
|
|
213
|
+
applyStepOutput(parentCtx, this, result);
|
|
214
|
+
return {
|
|
215
|
+
success: true,
|
|
216
|
+
data: dispatchData,
|
|
217
|
+
error: null,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=SubworkflowNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SubworkflowNode.js","sourceRoot":"","sources":["../src/SubworkflowNode.ts"],"names":[],"mappings":"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"}
|