@bian-womp/spark-graph 0.3.73 → 0.3.74
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/lib/cjs/index.cjs +154 -81
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/NodeExecutor.d.ts.map +1 -1
- package/lib/cjs/src/runtime/components/RunContextManager.d.ts +6 -0
- package/lib/cjs/src/runtime/components/RunContextManager.d.ts.map +1 -1
- package/lib/esm/index.js +154 -81
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/NodeExecutor.d.ts.map +1 -1
- package/lib/esm/src/runtime/components/RunContextManager.d.ts +6 -0
- package/lib/esm/src/runtime/components/RunContextManager.d.ts.map +1 -1
- package/package.json +2 -2
package/lib/cjs/index.cjs
CHANGED
|
@@ -1684,6 +1684,7 @@ class RunContextManager {
|
|
|
1684
1684
|
id,
|
|
1685
1685
|
startNodes: new Set([startNodeId]),
|
|
1686
1686
|
cancelledNodes: new Set(),
|
|
1687
|
+
pendingScheduling: 1,
|
|
1687
1688
|
pendingNodes: 0,
|
|
1688
1689
|
pendingEdges: 0,
|
|
1689
1690
|
pendingResolvers: 0,
|
|
@@ -1719,6 +1720,33 @@ class RunContextManager {
|
|
|
1719
1720
|
hasActiveRunContexts() {
|
|
1720
1721
|
return this.runContexts.size > 0;
|
|
1721
1722
|
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Release one scheduling hold from a run-context.
|
|
1725
|
+
* Must be called once by the creator when scheduling decisions are complete.
|
|
1726
|
+
*/
|
|
1727
|
+
releaseScheduling(id) {
|
|
1728
|
+
const ctx = this.runContexts.get(id);
|
|
1729
|
+
if (!ctx) {
|
|
1730
|
+
this.logger.debug("release-scheduling-context-not-found", {
|
|
1731
|
+
runContextId: id,
|
|
1732
|
+
});
|
|
1733
|
+
return;
|
|
1734
|
+
}
|
|
1735
|
+
if (ctx.pendingScheduling > 0) {
|
|
1736
|
+
ctx.pendingScheduling--;
|
|
1737
|
+
}
|
|
1738
|
+
else {
|
|
1739
|
+
this.logger.warn("release-scheduling-underflow", {
|
|
1740
|
+
runContextId: id,
|
|
1741
|
+
pendingScheduling: ctx.pendingScheduling,
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
this.logger.debug("release-scheduling", {
|
|
1745
|
+
runContextId: id,
|
|
1746
|
+
pendingScheduling: ctx.pendingScheduling,
|
|
1747
|
+
});
|
|
1748
|
+
this.finishRunContextIfPossible(id);
|
|
1749
|
+
}
|
|
1722
1750
|
/**
|
|
1723
1751
|
* Increment queued work count for a run-context.
|
|
1724
1752
|
* Used by asyncConcurrency: "queue" to keep contexts alive while work is queued.
|
|
@@ -1870,7 +1898,11 @@ class RunContextManager {
|
|
|
1870
1898
|
});
|
|
1871
1899
|
return;
|
|
1872
1900
|
}
|
|
1873
|
-
if (ctx.
|
|
1901
|
+
if (ctx.pendingScheduling > 0 ||
|
|
1902
|
+
ctx.pendingNodes > 0 ||
|
|
1903
|
+
ctx.pendingEdges > 0 ||
|
|
1904
|
+
ctx.pendingResolvers > 0 ||
|
|
1905
|
+
ctx.pendingQueued > 0) {
|
|
1874
1906
|
return; // Still has pending work
|
|
1875
1907
|
}
|
|
1876
1908
|
this.logger.info("finish-run-context", {
|
|
@@ -2980,13 +3012,22 @@ class NodeExecutor {
|
|
|
2980
3012
|
execute: (opts) => {
|
|
2981
3013
|
if (this.graph.allInboundHaveValue(nodeId)) {
|
|
2982
3014
|
let runContextIdsToUse = this.runtime.getRunMode() === "auto" ? undefined : runContextIds;
|
|
3015
|
+
let runContextIdToRelease;
|
|
2983
3016
|
if (this.runtime.getRunMode() === "manual" && (!runContextIds || runContextIds.size === 0)) {
|
|
2984
|
-
|
|
3017
|
+
runContextIdToRelease = this.runContextManager.createRunContext(nodeId, opts);
|
|
3018
|
+
runContextIdsToUse = new Set([runContextIdToRelease]);
|
|
3019
|
+
}
|
|
3020
|
+
try {
|
|
3021
|
+
this.execute(nodeId, {
|
|
3022
|
+
runContextIds: runContextIdsToUse,
|
|
3023
|
+
reason: opts?.reason ?? "executeFromContext",
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
finally {
|
|
3027
|
+
if (runContextIdToRelease) {
|
|
3028
|
+
this.runContextManager.releaseScheduling(runContextIdToRelease);
|
|
3029
|
+
}
|
|
2985
3030
|
}
|
|
2986
|
-
this.execute(nodeId, {
|
|
2987
|
-
runContextIds: runContextIdsToUse,
|
|
2988
|
-
reason: opts?.reason ?? "executeFromContext",
|
|
2989
|
-
});
|
|
2990
3031
|
}
|
|
2991
3032
|
},
|
|
2992
3033
|
getInput: (handle) => inputs[handle],
|
|
@@ -3012,6 +3053,7 @@ class NodeExecutor {
|
|
|
3012
3053
|
*/
|
|
3013
3054
|
execute(nodeId, opts) {
|
|
3014
3055
|
let { runContextIds, canSkipHandleResolution, reason = "" } = opts ?? {};
|
|
3056
|
+
let autoCreatedRunContextId;
|
|
3015
3057
|
const node = this.graph.getNode(nodeId);
|
|
3016
3058
|
if (!node)
|
|
3017
3059
|
return;
|
|
@@ -3024,81 +3066,89 @@ class NodeExecutor {
|
|
|
3024
3066
|
if (runMode === "manual" && (!runContextIds || runContextIds.size === 0)) {
|
|
3025
3067
|
// If autoRun is true, auto-generate a run context (similar to createExecutionContext pattern)
|
|
3026
3068
|
if (node.policy?.autoRun === true) {
|
|
3027
|
-
|
|
3069
|
+
autoCreatedRunContextId = this.runContextManager.createRunContext(nodeId, { propagate: false });
|
|
3070
|
+
runContextIds = new Set([autoCreatedRunContextId]);
|
|
3028
3071
|
}
|
|
3029
3072
|
else {
|
|
3030
3073
|
console.trace(`NodeExecutor.execute[${formatNodeRef(this.graph, nodeId)}:${reason}]: no runContextIds provided in manual mode, skipping execution`);
|
|
3031
3074
|
return;
|
|
3032
3075
|
}
|
|
3033
3076
|
}
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
// Early validation for auto-mode paused state
|
|
3039
|
-
if (this.runtime.isPaused())
|
|
3040
|
-
return;
|
|
3041
|
-
// Check runtime validators (check current state, not just graph definition)
|
|
3042
|
-
const runtimeValidationError = this.runtime.hasRuntimeValidationBlock(nodeId);
|
|
3043
|
-
if (runtimeValidationError) {
|
|
3044
|
-
this.eventEmitter.emit("error", {
|
|
3045
|
-
kind: "system",
|
|
3046
|
-
message: runtimeValidationError.message,
|
|
3047
|
-
code: runtimeValidationError.code || "RUNTIME_VALIDATION_BLOCKED",
|
|
3048
|
-
details: {
|
|
3049
|
-
nodeId,
|
|
3050
|
-
nodeTypeId: node?.typeId,
|
|
3051
|
-
...runtimeValidationError.details,
|
|
3052
|
-
},
|
|
3053
|
-
});
|
|
3054
|
-
return;
|
|
3055
|
-
}
|
|
3056
|
-
// Attach run-context IDs if provided - do this BEFORE checking for pending resolution
|
|
3057
|
-
// so that handle resolution can track these run contexts
|
|
3058
|
-
if (runContextIds) {
|
|
3059
|
-
this.graph.addNodeRunContextIds(nodeId, runContextIds);
|
|
3060
|
-
}
|
|
3061
|
-
if (!canSkipHandleResolution && !this.handleResolver.getPendingResolution(nodeId)) {
|
|
3062
|
-
this.handleResolver.scheduleRecomputeHandles(nodeId);
|
|
3063
|
-
}
|
|
3064
|
-
// Check if handles are being resolved - wait for resolution before executing
|
|
3065
|
-
// Do this AFTER setting up run contexts so handle resolution can track them
|
|
3066
|
-
const pendingResolution = this.handleResolver.getPendingResolution(nodeId);
|
|
3067
|
-
if (pendingResolution) {
|
|
3068
|
-
if (runContextIds && runContextIds.size > 0) {
|
|
3069
|
-
for (const id of runContextIds) {
|
|
3070
|
-
this.runContextManager.startHandleResolution(id, nodeId);
|
|
3071
|
-
}
|
|
3077
|
+
try {
|
|
3078
|
+
if (runMode === "auto" && runContextIds && runContextIds.size > 0) {
|
|
3079
|
+
console.trace(`NodeExecutor.execute[${formatNodeRef(this.graph, nodeId)}:${reason}]: runContextIds provided in auto mode, ignoring`);
|
|
3080
|
+
runContextIds = undefined;
|
|
3072
3081
|
}
|
|
3073
|
-
//
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3082
|
+
// Early validation for auto-mode paused state
|
|
3083
|
+
if (this.runtime.isPaused())
|
|
3084
|
+
return;
|
|
3085
|
+
// Check runtime validators (check current state, not just graph definition)
|
|
3086
|
+
const runtimeValidationError = this.runtime.hasRuntimeValidationBlock(nodeId);
|
|
3087
|
+
if (runtimeValidationError) {
|
|
3088
|
+
this.eventEmitter.emit("error", {
|
|
3089
|
+
kind: "system",
|
|
3090
|
+
message: runtimeValidationError.message,
|
|
3091
|
+
code: runtimeValidationError.code || "RUNTIME_VALIDATION_BLOCKED",
|
|
3092
|
+
details: {
|
|
3093
|
+
nodeId,
|
|
3094
|
+
nodeTypeId: node?.typeId,
|
|
3095
|
+
...runtimeValidationError.details,
|
|
3096
|
+
},
|
|
3097
|
+
});
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
// Attach run-context IDs if provided - do this BEFORE checking for pending resolution
|
|
3101
|
+
// so that handle resolution can track these run contexts
|
|
3102
|
+
if (runContextIds) {
|
|
3103
|
+
this.graph.addNodeRunContextIds(nodeId, runContextIds);
|
|
3104
|
+
}
|
|
3105
|
+
if (!canSkipHandleResolution && !this.handleResolver.getPendingResolution(nodeId)) {
|
|
3106
|
+
this.handleResolver.scheduleRecomputeHandles(nodeId);
|
|
3107
|
+
}
|
|
3108
|
+
// Check if handles are being resolved - wait for resolution before executing
|
|
3109
|
+
// Do this AFTER setting up run contexts so handle resolution can track them
|
|
3110
|
+
const pendingResolution = this.handleResolver.getPendingResolution(nodeId);
|
|
3111
|
+
if (pendingResolution) {
|
|
3084
3112
|
if (runContextIds && runContextIds.size > 0) {
|
|
3085
3113
|
for (const id of runContextIds) {
|
|
3086
|
-
this.runContextManager.
|
|
3114
|
+
this.runContextManager.startHandleResolution(id, nodeId);
|
|
3087
3115
|
}
|
|
3088
3116
|
}
|
|
3089
|
-
|
|
3090
|
-
|
|
3117
|
+
// Wait for resolution to complete, then re-execute
|
|
3118
|
+
pendingResolution.then(() => {
|
|
3119
|
+
// Re-check node still exists and conditions
|
|
3120
|
+
const nodeAfter = this.graph.getNode(nodeId);
|
|
3121
|
+
if (nodeAfter) {
|
|
3122
|
+
this.execute(nodeId, {
|
|
3123
|
+
runContextIds,
|
|
3124
|
+
canSkipHandleResolution: true,
|
|
3125
|
+
reason: opts?.reason,
|
|
3126
|
+
});
|
|
3127
|
+
}
|
|
3128
|
+
if (runContextIds && runContextIds.size > 0) {
|
|
3129
|
+
for (const id of runContextIds) {
|
|
3130
|
+
this.runContextManager.finishHandleResolution(id, nodeId);
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
});
|
|
3134
|
+
return;
|
|
3135
|
+
}
|
|
3136
|
+
// Handle debouncing
|
|
3137
|
+
const now = Date.now();
|
|
3138
|
+
if (this.shouldDebounce(nodeId, now)) {
|
|
3139
|
+
this.handleDebouncedSchedule(nodeId, now, runContextIds, reason);
|
|
3140
|
+
return;
|
|
3141
|
+
}
|
|
3142
|
+
// Prepare execution plan
|
|
3143
|
+
const executionPlan = this.prepareExecutionPlan(nodeId, runContextIds, now, reason);
|
|
3144
|
+
// Route to appropriate concurrency handler
|
|
3145
|
+
this.routeToConcurrencyHandler(nodeId, executionPlan);
|
|
3091
3146
|
}
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
return;
|
|
3147
|
+
finally {
|
|
3148
|
+
if (autoCreatedRunContextId) {
|
|
3149
|
+
this.runContextManager.releaseScheduling(autoCreatedRunContextId);
|
|
3150
|
+
}
|
|
3097
3151
|
}
|
|
3098
|
-
// Prepare execution plan
|
|
3099
|
-
const executionPlan = this.prepareExecutionPlan(nodeId, runContextIds, now, reason);
|
|
3100
|
-
// Route to appropriate concurrency handler
|
|
3101
|
-
this.routeToConcurrencyHandler(nodeId, executionPlan);
|
|
3102
3152
|
}
|
|
3103
3153
|
/**
|
|
3104
3154
|
* Check if execution should be debounced
|
|
@@ -3716,16 +3766,26 @@ class GraphRuntime {
|
|
|
3716
3766
|
executeNodeAutoRun(nodeId, opts) {
|
|
3717
3767
|
const node = this.graph.getNode(nodeId);
|
|
3718
3768
|
const shouldAutoRun = this.runMode === "auto" || node?.policy?.autoRun === true;
|
|
3769
|
+
const canExecute = this.graph.allInboundHaveValue(nodeId);
|
|
3770
|
+
if (!shouldAutoRun || !canExecute)
|
|
3771
|
+
return;
|
|
3719
3772
|
let runContextIdsToUse = undefined;
|
|
3773
|
+
let runContextIdToRelease;
|
|
3720
3774
|
if (this.runMode === "manual") {
|
|
3721
|
-
|
|
3775
|
+
runContextIdToRelease = this.runContextManager.createRunContext(nodeId, { propagate: false });
|
|
3776
|
+
runContextIdsToUse = new Set([runContextIdToRelease]);
|
|
3722
3777
|
}
|
|
3723
|
-
|
|
3778
|
+
try {
|
|
3724
3779
|
this.execute(nodeId, {
|
|
3725
3780
|
runContextIds: runContextIdsToUse,
|
|
3726
3781
|
reason: opts?.reason ?? "executeNodeAutoRun",
|
|
3727
3782
|
});
|
|
3728
3783
|
}
|
|
3784
|
+
finally {
|
|
3785
|
+
if (runContextIdToRelease) {
|
|
3786
|
+
this.runContextManager.releaseScheduling(runContextIdToRelease);
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3729
3789
|
}
|
|
3730
3790
|
setInputs(nodeId, inputs) {
|
|
3731
3791
|
const node = this.graph.getNode(nodeId);
|
|
@@ -3810,8 +3870,9 @@ class GraphRuntime {
|
|
|
3810
3870
|
});
|
|
3811
3871
|
if (this.runMode === "auto" && invalidate) {
|
|
3812
3872
|
for (const nodeId of this.graph.getNodeIds()) {
|
|
3813
|
-
if (this.graph.allInboundHaveValue(nodeId))
|
|
3873
|
+
if (this.graph.allInboundHaveValue(nodeId)) {
|
|
3814
3874
|
this.execute(nodeId, { reason: "launch" });
|
|
3875
|
+
}
|
|
3815
3876
|
}
|
|
3816
3877
|
}
|
|
3817
3878
|
if (startPaused) {
|
|
@@ -3958,10 +4019,15 @@ class GraphRuntime {
|
|
|
3958
4019
|
...opts,
|
|
3959
4020
|
});
|
|
3960
4021
|
this.graph.addNodeRunContextId(startNodeId, id);
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
4022
|
+
try {
|
|
4023
|
+
this.execute(startNodeId, {
|
|
4024
|
+
runContextIds: new Set([id]),
|
|
4025
|
+
reason: opts?.reason ?? "runFromHereContext",
|
|
4026
|
+
});
|
|
4027
|
+
}
|
|
4028
|
+
finally {
|
|
4029
|
+
this.runContextManager.releaseScheduling(id);
|
|
4030
|
+
}
|
|
3965
4031
|
});
|
|
3966
4032
|
}
|
|
3967
4033
|
setRunMode(runMode) {
|
|
@@ -4282,14 +4348,21 @@ class GraphRuntime {
|
|
|
4282
4348
|
const val = this.getOutput(nodeId, handle);
|
|
4283
4349
|
if (val !== undefined) {
|
|
4284
4350
|
let runContextIdsToUse = undefined;
|
|
4351
|
+
let runContextIdToRelease;
|
|
4285
4352
|
if (this.runMode === "manual") {
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4353
|
+
runContextIdToRelease = this.runContextManager.createRunContext(nodeId, {
|
|
4354
|
+
propagate: false,
|
|
4355
|
+
});
|
|
4356
|
+
runContextIdsToUse = new Set([runContextIdToRelease]);
|
|
4357
|
+
}
|
|
4358
|
+
try {
|
|
4359
|
+
this.propagate(nodeId, handle, val, runContextIdsToUse);
|
|
4360
|
+
}
|
|
4361
|
+
finally {
|
|
4362
|
+
if (runContextIdToRelease) {
|
|
4363
|
+
this.runContextManager.releaseScheduling(runContextIdToRelease);
|
|
4364
|
+
}
|
|
4291
4365
|
}
|
|
4292
|
-
this.propagate(nodeId, handle, val, runContextIdsToUse);
|
|
4293
4366
|
}
|
|
4294
4367
|
}
|
|
4295
4368
|
}
|