@langchain/langgraph 0.2.41 → 0.2.43-rc.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/README.md +237 -154
- package/dist/channels/any_value.cjs +10 -10
- package/dist/channels/any_value.d.ts +1 -1
- package/dist/channels/any_value.js +10 -10
- package/dist/channels/ephemeral_value.cjs +10 -9
- package/dist/channels/ephemeral_value.d.ts +1 -1
- package/dist/channels/ephemeral_value.js +10 -9
- package/dist/channels/last_value.cjs +8 -7
- package/dist/channels/last_value.d.ts +1 -1
- package/dist/channels/last_value.js +8 -7
- package/dist/constants.cjs +33 -6
- package/dist/constants.d.ts +17 -2
- package/dist/constants.js +32 -5
- package/dist/errors.d.ts +3 -3
- package/dist/func/index.cjs +272 -0
- package/dist/func/index.d.ts +310 -0
- package/dist/func/index.js +267 -0
- package/dist/func/types.cjs +15 -0
- package/dist/func/types.d.ts +59 -0
- package/dist/func/types.js +11 -0
- package/dist/graph/graph.cjs +31 -35
- package/dist/graph/graph.d.ts +1 -5
- package/dist/graph/graph.js +1 -5
- package/dist/graph/index.cjs +1 -3
- package/dist/graph/index.d.ts +1 -1
- package/dist/graph/index.js +1 -1
- package/dist/graph/message.d.ts +1 -1
- package/dist/graph/state.cjs +17 -17
- package/dist/graph/state.d.ts +2 -1
- package/dist/graph/state.js +2 -2
- package/dist/index.cjs +8 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/interrupt.cjs +21 -34
- package/dist/interrupt.d.ts +1 -1
- package/dist/interrupt.js +22 -35
- package/dist/prebuilt/agent_executor.cjs +3 -3
- package/dist/prebuilt/agent_executor.d.ts +1 -1
- package/dist/prebuilt/agent_executor.js +1 -1
- package/dist/prebuilt/chat_agent_executor.cjs +3 -3
- package/dist/prebuilt/chat_agent_executor.d.ts +1 -1
- package/dist/prebuilt/chat_agent_executor.js +1 -1
- package/dist/prebuilt/react_agent_executor.cjs +33 -8
- package/dist/prebuilt/react_agent_executor.d.ts +4 -1
- package/dist/prebuilt/react_agent_executor.js +31 -6
- package/dist/prebuilt/tool_node.cjs +1 -2
- package/dist/prebuilt/tool_node.d.ts +1 -1
- package/dist/prebuilt/tool_node.js +1 -2
- package/dist/pregel/algo.cjs +121 -12
- package/dist/pregel/algo.d.ts +8 -6
- package/dist/pregel/algo.js +122 -13
- package/dist/pregel/call.cjs +77 -0
- package/dist/pregel/call.d.ts +15 -0
- package/dist/pregel/call.js +71 -0
- package/dist/pregel/index.cjs +59 -96
- package/dist/pregel/index.d.ts +1 -10
- package/dist/pregel/index.js +61 -98
- package/dist/pregel/io.cjs +6 -1
- package/dist/pregel/io.js +7 -2
- package/dist/pregel/loop.cjs +109 -75
- package/dist/pregel/loop.d.ts +17 -23
- package/dist/pregel/loop.js +110 -75
- package/dist/pregel/messages.d.ts +1 -1
- package/dist/pregel/retry.cjs +22 -50
- package/dist/pregel/retry.d.ts +6 -6
- package/dist/pregel/retry.js +22 -50
- package/dist/pregel/runner.cjs +275 -0
- package/dist/pregel/runner.d.ts +64 -0
- package/dist/pregel/runner.js +271 -0
- package/dist/pregel/stream.cjs +71 -0
- package/dist/pregel/stream.d.ts +17 -0
- package/dist/pregel/stream.js +67 -0
- package/dist/pregel/types.cjs +54 -0
- package/dist/pregel/types.d.ts +78 -6
- package/dist/pregel/types.js +51 -1
- package/dist/pregel/utils/config.cjs +26 -1
- package/dist/pregel/utils/config.d.ts +14 -0
- package/dist/pregel/utils/config.js +22 -0
- package/dist/pregel/write.d.ts +1 -1
- package/dist/utils.cjs +15 -1
- package/dist/utils.d.ts +3 -1
- package/dist/utils.js +12 -0
- package/dist/web.cjs +7 -5
- package/dist/web.d.ts +4 -4
- package/dist/web.js +3 -3
- package/package.json +8 -8
package/dist/pregel/loop.js
CHANGED
|
@@ -1,70 +1,16 @@
|
|
|
1
|
-
import { IterableReadableStream } from "@langchain/core/utils/stream";
|
|
2
1
|
import { copyCheckpoint, emptyCheckpoint, AsyncBatchedStore, WRITES_IDX_MAP, } from "@langchain/langgraph-checkpoint";
|
|
3
2
|
import { createCheckpoint, emptyChannels, } from "../channels/base.js";
|
|
4
|
-
import { isCommand, CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, NULL_TASK_ID, RESUME, TAG_HIDDEN, } from "../constants.js";
|
|
5
|
-
import { _applyWrites, _prepareNextTasks, increment, shouldInterrupt, } from "./algo.js";
|
|
3
|
+
import { isCommand, CHECKPOINT_NAMESPACE_SEPARATOR, CONFIG_KEY_CHECKPOINT_MAP, CONFIG_KEY_READ, CONFIG_KEY_RESUMING, CONFIG_KEY_STREAM, ERROR, INPUT, INTERRUPT, NULL_TASK_ID, RESUME, TAG_HIDDEN, PUSH, CONFIG_KEY_SCRATCHPAD, } from "../constants.js";
|
|
4
|
+
import { _applyWrites, _prepareNextTasks, _prepareSingleTask, increment, shouldInterrupt, } from "./algo.js";
|
|
6
5
|
import { gatherIterator, gatherIteratorSync, prefixGenerator, } from "../utils.js";
|
|
7
6
|
import { mapCommand, mapInput, mapOutputUpdates, mapOutputValues, readChannels, } from "./io.js";
|
|
8
7
|
import { getSubgraphsSeenSet, EmptyInputError, GraphInterrupt, isGraphInterrupt, MultipleSubgraphsError, } from "../errors.js";
|
|
9
8
|
import { getNewChannelVersions, patchConfigurable } from "./utils/index.js";
|
|
10
|
-
import { mapDebugTasks, mapDebugCheckpoint, mapDebugTaskResults, } from "./debug.js";
|
|
9
|
+
import { mapDebugTasks, mapDebugCheckpoint, mapDebugTaskResults, printStepTasks, } from "./debug.js";
|
|
10
|
+
import { IterableReadableWritableStream } from "./stream.js";
|
|
11
11
|
const INPUT_DONE = Symbol.for("INPUT_DONE");
|
|
12
12
|
const INPUT_RESUMING = Symbol.for("INPUT_RESUMING");
|
|
13
13
|
const DEFAULT_LOOP_LIMIT = 25;
|
|
14
|
-
export class IterableReadableWritableStream extends IterableReadableStream {
|
|
15
|
-
constructor(params) {
|
|
16
|
-
let streamControllerPromiseResolver;
|
|
17
|
-
const streamControllerPromise = new Promise((resolve) => {
|
|
18
|
-
streamControllerPromiseResolver = resolve;
|
|
19
|
-
});
|
|
20
|
-
super({
|
|
21
|
-
start: (controller) => {
|
|
22
|
-
streamControllerPromiseResolver(controller);
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
|
-
Object.defineProperty(this, "modes", {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
configurable: true,
|
|
28
|
-
writable: true,
|
|
29
|
-
value: void 0
|
|
30
|
-
});
|
|
31
|
-
Object.defineProperty(this, "controller", {
|
|
32
|
-
enumerable: true,
|
|
33
|
-
configurable: true,
|
|
34
|
-
writable: true,
|
|
35
|
-
value: void 0
|
|
36
|
-
});
|
|
37
|
-
Object.defineProperty(this, "passthroughFn", {
|
|
38
|
-
enumerable: true,
|
|
39
|
-
configurable: true,
|
|
40
|
-
writable: true,
|
|
41
|
-
value: void 0
|
|
42
|
-
});
|
|
43
|
-
// .start() will always be called before the stream can be interacted
|
|
44
|
-
// with anyway
|
|
45
|
-
void streamControllerPromise.then((controller) => {
|
|
46
|
-
this.controller = controller;
|
|
47
|
-
});
|
|
48
|
-
this.passthroughFn = params.passthroughFn;
|
|
49
|
-
this.modes = params.modes;
|
|
50
|
-
}
|
|
51
|
-
push(chunk) {
|
|
52
|
-
this.passthroughFn?.(chunk);
|
|
53
|
-
this.controller.enqueue(chunk);
|
|
54
|
-
}
|
|
55
|
-
close() {
|
|
56
|
-
try {
|
|
57
|
-
this.controller.close();
|
|
58
|
-
}
|
|
59
|
-
catch (e) {
|
|
60
|
-
// pass
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
-
error(e) {
|
|
65
|
-
this.controller.error(e);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
14
|
function createDuplexStream(...streams) {
|
|
69
15
|
return new IterableReadableWritableStream({
|
|
70
16
|
passthroughFn: (value) => {
|
|
@@ -245,6 +191,36 @@ export class PregelLoop {
|
|
|
245
191
|
writable: true,
|
|
246
192
|
value: void 0
|
|
247
193
|
});
|
|
194
|
+
Object.defineProperty(this, "manager", {
|
|
195
|
+
enumerable: true,
|
|
196
|
+
configurable: true,
|
|
197
|
+
writable: true,
|
|
198
|
+
value: void 0
|
|
199
|
+
});
|
|
200
|
+
Object.defineProperty(this, "interruptAfter", {
|
|
201
|
+
enumerable: true,
|
|
202
|
+
configurable: true,
|
|
203
|
+
writable: true,
|
|
204
|
+
value: void 0
|
|
205
|
+
});
|
|
206
|
+
Object.defineProperty(this, "interruptBefore", {
|
|
207
|
+
enumerable: true,
|
|
208
|
+
configurable: true,
|
|
209
|
+
writable: true,
|
|
210
|
+
value: void 0
|
|
211
|
+
});
|
|
212
|
+
Object.defineProperty(this, "toInterrupt", {
|
|
213
|
+
enumerable: true,
|
|
214
|
+
configurable: true,
|
|
215
|
+
writable: true,
|
|
216
|
+
value: []
|
|
217
|
+
});
|
|
218
|
+
Object.defineProperty(this, "debug", {
|
|
219
|
+
enumerable: true,
|
|
220
|
+
configurable: true,
|
|
221
|
+
writable: true,
|
|
222
|
+
value: false
|
|
223
|
+
});
|
|
248
224
|
this.input = params.input;
|
|
249
225
|
this.checkpointer = params.checkpointer;
|
|
250
226
|
// TODO: if managed values no longer needs graph we can replace with
|
|
@@ -266,6 +242,7 @@ export class PregelLoop {
|
|
|
266
242
|
this.config = params.config;
|
|
267
243
|
this.checkpointConfig = params.checkpointConfig;
|
|
268
244
|
this.isNested = params.isNested;
|
|
245
|
+
this.manager = params.manager;
|
|
269
246
|
this.outputKeys = params.outputKeys;
|
|
270
247
|
this.streamKeys = params.streamKeys;
|
|
271
248
|
this.nodes = params.nodes;
|
|
@@ -274,6 +251,9 @@ export class PregelLoop {
|
|
|
274
251
|
this.stream = params.stream;
|
|
275
252
|
this.checkpointNamespace = params.checkpointNamespace;
|
|
276
253
|
this.prevCheckpointConfig = params.prevCheckpointConfig;
|
|
254
|
+
this.interruptAfter = params.interruptAfter;
|
|
255
|
+
this.interruptBefore = params.interruptBefore;
|
|
256
|
+
this.debug = params.debug;
|
|
277
257
|
}
|
|
278
258
|
static async initialize(params) {
|
|
279
259
|
let { config, stream } = params;
|
|
@@ -364,6 +344,7 @@ export class PregelLoop {
|
|
|
364
344
|
channels,
|
|
365
345
|
managed: params.managed,
|
|
366
346
|
isNested,
|
|
347
|
+
manager: params.manager,
|
|
367
348
|
skipDoneTasks,
|
|
368
349
|
step,
|
|
369
350
|
stop,
|
|
@@ -374,6 +355,9 @@ export class PregelLoop {
|
|
|
374
355
|
nodes: params.nodes,
|
|
375
356
|
stream,
|
|
376
357
|
store,
|
|
358
|
+
interruptAfter: params.interruptAfter,
|
|
359
|
+
interruptBefore: params.interruptBefore,
|
|
360
|
+
debug: params.debug,
|
|
377
361
|
});
|
|
378
362
|
}
|
|
379
363
|
_checkpointerPutAfterPrevious(input) {
|
|
@@ -454,7 +438,7 @@ export class PregelLoop {
|
|
|
454
438
|
if (this.store && !this.store.isRunning) {
|
|
455
439
|
this.store?.start();
|
|
456
440
|
}
|
|
457
|
-
const { inputKeys = []
|
|
441
|
+
const { inputKeys = [] } = params;
|
|
458
442
|
if (this.status !== "pending") {
|
|
459
443
|
throw new Error(`Cannot tick when status is no longer "pending". Current status: "${this.status}"`);
|
|
460
444
|
}
|
|
@@ -478,7 +462,7 @@ export class PregelLoop {
|
|
|
478
462
|
writes: mapOutputUpdates(this.outputKeys, Object.values(this.tasks).map((task) => [task, task.writes])).next().value ?? null,
|
|
479
463
|
});
|
|
480
464
|
// after execution, check if we should interrupt
|
|
481
|
-
if (shouldInterrupt(this.checkpoint, interruptAfter, Object.values(this.tasks))) {
|
|
465
|
+
if (shouldInterrupt(this.checkpoint, this.interruptAfter, Object.values(this.tasks))) {
|
|
482
466
|
this.status = "interrupt_after";
|
|
483
467
|
throw new GraphInterrupt();
|
|
484
468
|
}
|
|
@@ -494,8 +478,9 @@ export class PregelLoop {
|
|
|
494
478
|
step: this.step,
|
|
495
479
|
checkpointer: this.checkpointer,
|
|
496
480
|
isResuming: this.input === INPUT_RESUMING,
|
|
497
|
-
manager,
|
|
481
|
+
manager: this.manager,
|
|
498
482
|
store: this.store,
|
|
483
|
+
stream: this.stream,
|
|
499
484
|
});
|
|
500
485
|
this.tasks = nextTasks;
|
|
501
486
|
// Produce debug output
|
|
@@ -526,15 +511,10 @@ export class PregelLoop {
|
|
|
526
511
|
}
|
|
527
512
|
// if all tasks have finished, re-tick
|
|
528
513
|
if (Object.values(this.tasks).every((task) => task.writes.length > 0)) {
|
|
529
|
-
return this.tick({
|
|
530
|
-
inputKeys,
|
|
531
|
-
interruptAfter,
|
|
532
|
-
interruptBefore,
|
|
533
|
-
manager,
|
|
534
|
-
});
|
|
514
|
+
return this.tick({ inputKeys });
|
|
535
515
|
}
|
|
536
516
|
// Before execution, check if we should interrupt
|
|
537
|
-
if (shouldInterrupt(this.checkpoint, interruptBefore, Object.values(this.tasks))) {
|
|
517
|
+
if (shouldInterrupt(this.checkpoint, this.interruptBefore, Object.values(this.tasks))) {
|
|
538
518
|
this.status = "interrupt_before";
|
|
539
519
|
throw new GraphInterrupt();
|
|
540
520
|
}
|
|
@@ -571,20 +551,59 @@ export class PregelLoop {
|
|
|
571
551
|
}
|
|
572
552
|
return suppress;
|
|
573
553
|
}
|
|
554
|
+
acceptPush(task, writeIdx, call) {
|
|
555
|
+
if (this.interruptAfter?.length > 0 &&
|
|
556
|
+
shouldInterrupt(this.checkpoint, this.interruptAfter, [task])) {
|
|
557
|
+
this.toInterrupt.push(task);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const pushed = _prepareSingleTask([PUSH, task.path ?? [], writeIdx, task.id, call], this.checkpoint, this.checkpointPendingWrites, this.nodes, this.channels, this.managed, this.config, true, {
|
|
561
|
+
step: this.step,
|
|
562
|
+
checkpointer: this.checkpointer,
|
|
563
|
+
manager: this.manager,
|
|
564
|
+
store: this.store,
|
|
565
|
+
stream: this.stream,
|
|
566
|
+
});
|
|
567
|
+
if (pushed) {
|
|
568
|
+
if (this.interruptBefore?.length > 0 &&
|
|
569
|
+
shouldInterrupt(this.checkpoint, this.interruptBefore, [pushed])) {
|
|
570
|
+
this.toInterrupt.push(pushed);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
this._emit(gatherIteratorSync(prefixGenerator(mapDebugTasks(this.step, [pushed]), "debug")));
|
|
574
|
+
if (this.debug) {
|
|
575
|
+
printStepTasks(this.step, [pushed]);
|
|
576
|
+
}
|
|
577
|
+
this.tasks[pushed.id] = pushed;
|
|
578
|
+
if (this.skipDoneTasks) {
|
|
579
|
+
this._matchWrites({ [pushed.id]: pushed });
|
|
580
|
+
}
|
|
581
|
+
return pushed;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
574
584
|
_suppressInterrupt(e) {
|
|
575
585
|
return isGraphInterrupt(e) && !this.isNested;
|
|
576
586
|
}
|
|
577
|
-
/**
|
|
578
|
-
* Resuming from previous checkpoint requires
|
|
579
|
-
* - finding a previous checkpoint
|
|
580
|
-
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
581
|
-
*/
|
|
582
587
|
async _first(inputKeys) {
|
|
588
|
+
/*
|
|
589
|
+
* Resuming from previous checkpoint requires
|
|
590
|
+
* - finding a previous checkpoint
|
|
591
|
+
* - receiving null input (outer graph) or RESUMING flag (subgraph)
|
|
592
|
+
*/
|
|
593
|
+
const { configurable } = this.config;
|
|
583
594
|
const isResuming = Object.keys(this.checkpoint.channel_versions).length !== 0 &&
|
|
584
595
|
(this.config.configurable?.[CONFIG_KEY_RESUMING] !== undefined ||
|
|
585
596
|
this.input === null ||
|
|
586
597
|
isCommand(this.input));
|
|
598
|
+
// take resume value from parent
|
|
599
|
+
const scratchpad = configurable?.[CONFIG_KEY_SCRATCHPAD];
|
|
600
|
+
if (scratchpad && scratchpad.nullResume !== undefined) {
|
|
601
|
+
this.putWrites(NULL_TASK_ID, [[RESUME, scratchpad.nullResume]]);
|
|
602
|
+
}
|
|
587
603
|
if (isCommand(this.input)) {
|
|
604
|
+
if (this.input.resume != null && this.checkpointer == null) {
|
|
605
|
+
throw new Error("Cannot use Command(resume=...) without checkpointer");
|
|
606
|
+
}
|
|
588
607
|
const writes = {};
|
|
589
608
|
// group writes by task id
|
|
590
609
|
for (const [tid, key, value] of mapCommand(this.input, this.checkpointPendingWrites)) {
|
|
@@ -649,10 +668,10 @@ export class PregelLoop {
|
|
|
649
668
|
});
|
|
650
669
|
}
|
|
651
670
|
// done with input
|
|
652
|
-
this.input =
|
|
671
|
+
this.input = this.input === INPUT_RESUMING ? INPUT_RESUMING : INPUT_DONE;
|
|
653
672
|
if (!this.isNested) {
|
|
654
673
|
this.config = patchConfigurable(this.config, {
|
|
655
|
-
[CONFIG_KEY_RESUMING]:
|
|
674
|
+
[CONFIG_KEY_RESUMING]: this.input === INPUT_RESUMING,
|
|
656
675
|
});
|
|
657
676
|
}
|
|
658
677
|
}
|
|
@@ -713,4 +732,20 @@ export class PregelLoop {
|
|
|
713
732
|
}
|
|
714
733
|
this.step += 1;
|
|
715
734
|
}
|
|
735
|
+
_matchWrites(tasks) {
|
|
736
|
+
for (const [tid, k, v] of this.checkpointPendingWrites) {
|
|
737
|
+
if (k === ERROR || k === INTERRUPT || k === RESUME) {
|
|
738
|
+
continue;
|
|
739
|
+
}
|
|
740
|
+
const task = Object.values(tasks).find((t) => t.id === tid);
|
|
741
|
+
if (task) {
|
|
742
|
+
task.writes.push([k, v]);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
for (const task of Object.values(tasks)) {
|
|
746
|
+
if (task.writes.length > 0) {
|
|
747
|
+
this._outputWrites(task.id, task.writes, true);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
716
751
|
}
|
|
@@ -3,7 +3,7 @@ import { BaseMessage } from "@langchain/core/messages";
|
|
|
3
3
|
import { Serialized } from "@langchain/core/load/serializable";
|
|
4
4
|
import { LLMResult } from "@langchain/core/outputs";
|
|
5
5
|
import { ChainValues } from "@langchain/core/utils/types";
|
|
6
|
-
import { StreamChunk } from "./
|
|
6
|
+
import { StreamChunk } from "./stream.js";
|
|
7
7
|
type Meta = [string[], Record<string, any>];
|
|
8
8
|
/**
|
|
9
9
|
* A callback handler that implements stream_mode=messages.
|
package/dist/pregel/retry.cjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports._runWithRetry = exports.DEFAULT_MAX_RETRIES = exports.DEFAULT_MAX_INTERVAL = exports.DEFAULT_BACKOFF_FACTOR = exports.DEFAULT_INITIAL_INTERVAL = void 0;
|
|
4
4
|
const constants_js_1 = require("../constants.cjs");
|
|
5
5
|
const errors_js_1 = require("../errors.cjs");
|
|
6
|
+
const index_js_1 = require("./utils/index.cjs");
|
|
6
7
|
exports.DEFAULT_INITIAL_INTERVAL = 500;
|
|
7
8
|
exports.DEFAULT_BACKOFF_FACTOR = 2;
|
|
8
9
|
exports.DEFAULT_MAX_INTERVAL = 128000;
|
|
@@ -41,47 +42,9 @@ const DEFAULT_RETRY_ON_HANDLER = (error) => {
|
|
|
41
42
|
}
|
|
42
43
|
return true;
|
|
43
44
|
};
|
|
44
|
-
async function* executeTasksWithRetry(
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
46
|
-
tasks, options) {
|
|
47
|
-
const { stepTimeout, retryPolicy } = options ?? {};
|
|
48
|
-
let signal = options?.signal;
|
|
49
|
-
// Start tasks
|
|
50
|
-
const executingTasksMap = Object.fromEntries(tasks.map((pregelTask) => {
|
|
51
|
-
return [pregelTask.id, _runWithRetry(pregelTask, retryPolicy)];
|
|
52
|
-
}));
|
|
53
|
-
if (stepTimeout && signal) {
|
|
54
|
-
if ("any" in AbortSignal) {
|
|
55
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
56
|
-
signal = AbortSignal.any([
|
|
57
|
-
signal,
|
|
58
|
-
AbortSignal.timeout(stepTimeout),
|
|
59
|
-
]);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
else if (stepTimeout) {
|
|
63
|
-
signal = AbortSignal.timeout(stepTimeout);
|
|
64
|
-
}
|
|
65
|
-
// Abort if signal is aborted
|
|
66
|
-
signal?.throwIfAborted();
|
|
67
|
-
let listener;
|
|
68
|
-
const signalPromise = new Promise((_resolve, reject) => {
|
|
69
|
-
listener = () => reject(new Error("Abort"));
|
|
70
|
-
signal?.addEventListener("abort", listener);
|
|
71
|
-
}).finally(() => signal?.removeEventListener("abort", listener));
|
|
72
|
-
while (Object.keys(executingTasksMap).length > 0) {
|
|
73
|
-
const settledTask = await Promise.race([
|
|
74
|
-
...Object.values(executingTasksMap),
|
|
75
|
-
signalPromise,
|
|
76
|
-
]);
|
|
77
|
-
yield settledTask;
|
|
78
|
-
delete executingTasksMap[settledTask.task.id];
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
exports.executeTasksWithRetry = executeTasksWithRetry;
|
|
82
45
|
async function _runWithRetry(
|
|
83
46
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
-
pregelTask, retryPolicy) {
|
|
47
|
+
pregelTask, retryPolicy, configurable, signal) {
|
|
85
48
|
const resolvedRetryPolicy = pregelTask.retry_policy ?? retryPolicy;
|
|
86
49
|
let interval = resolvedRetryPolicy !== undefined
|
|
87
50
|
? resolvedRetryPolicy.initialInterval ?? exports.DEFAULT_INITIAL_INTERVAL
|
|
@@ -89,28 +52,34 @@ pregelTask, retryPolicy) {
|
|
|
89
52
|
let attempts = 0;
|
|
90
53
|
let error;
|
|
91
54
|
let result;
|
|
55
|
+
let { config } = pregelTask;
|
|
56
|
+
if (configurable) {
|
|
57
|
+
config = (0, index_js_1.patchConfigurable)(config, configurable);
|
|
58
|
+
}
|
|
92
59
|
// eslint-disable-next-line no-constant-condition
|
|
93
60
|
while (true) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
61
|
+
if (signal?.aborted) {
|
|
62
|
+
// no need to throw here - we'll throw from the runner, instead.
|
|
63
|
+
// there's just no point in retrying if the user has requested an abort.
|
|
64
|
+
break;
|
|
97
65
|
}
|
|
66
|
+
// Clear any writes from previous attempts
|
|
67
|
+
pregelTask.writes.splice(0, pregelTask.writes.length);
|
|
98
68
|
error = undefined;
|
|
99
69
|
try {
|
|
100
|
-
result = await pregelTask.proc.invoke(pregelTask.input,
|
|
70
|
+
result = await pregelTask.proc.invoke(pregelTask.input, config);
|
|
101
71
|
break;
|
|
102
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
72
|
}
|
|
104
73
|
catch (e) {
|
|
105
74
|
error = e;
|
|
106
75
|
error.pregelTaskId = pregelTask.id;
|
|
107
76
|
if ((0, errors_js_1.isParentCommand)(error)) {
|
|
108
|
-
const ns =
|
|
77
|
+
const ns = config?.configurable?.checkpoint_ns;
|
|
109
78
|
const cmd = error.command;
|
|
110
79
|
if (cmd.graph === ns) {
|
|
111
80
|
// this command is for the current graph, handle it
|
|
112
81
|
for (const writer of pregelTask.writers) {
|
|
113
|
-
await writer.invoke(cmd,
|
|
82
|
+
await writer.invoke(cmd, config);
|
|
114
83
|
}
|
|
115
84
|
break;
|
|
116
85
|
}
|
|
@@ -153,11 +122,13 @@ pregelTask, retryPolicy) {
|
|
|
153
122
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
154
123
|
error.constructor.unminifiable_name ??
|
|
155
124
|
error.constructor.name;
|
|
156
|
-
console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
|
|
125
|
+
console.log(`Retrying task "${String(pregelTask.name)}" after ${interval.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
|
|
126
|
+
// signal subgraphs to resume (if available)
|
|
127
|
+
config = (0, index_js_1.patchConfigurable)(config, { [constants_js_1.CONFIG_KEY_RESUMING]: true });
|
|
157
128
|
}
|
|
158
129
|
finally {
|
|
159
130
|
// Clear checkpoint_ns seen (for subgraph detection)
|
|
160
|
-
const checkpointNs =
|
|
131
|
+
const checkpointNs = config?.configurable?.checkpoint_ns;
|
|
161
132
|
if (checkpointNs) {
|
|
162
133
|
(0, errors_js_1.getSubgraphsSeenSet)().delete(checkpointNs);
|
|
163
134
|
}
|
|
@@ -166,6 +137,7 @@ pregelTask, retryPolicy) {
|
|
|
166
137
|
return {
|
|
167
138
|
task: pregelTask,
|
|
168
139
|
result,
|
|
169
|
-
error,
|
|
140
|
+
error: error,
|
|
170
141
|
};
|
|
171
142
|
}
|
|
143
|
+
exports._runWithRetry = _runWithRetry;
|
package/dist/pregel/retry.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PregelExecutableTask } from "./types.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type RetryPolicy } from "./utils/index.js";
|
|
3
3
|
export declare const DEFAULT_INITIAL_INTERVAL = 500;
|
|
4
4
|
export declare const DEFAULT_BACKOFF_FACTOR = 2;
|
|
5
5
|
export declare const DEFAULT_MAX_INTERVAL = 128000;
|
|
@@ -8,8 +8,8 @@ export type SettledPregelTask = {
|
|
|
8
8
|
task: PregelExecutableTask<any, any>;
|
|
9
9
|
error: Error;
|
|
10
10
|
};
|
|
11
|
-
export declare function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
11
|
+
export declare function _runWithRetry<N extends PropertyKey, C extends PropertyKey>(pregelTask: PregelExecutableTask<N, C>, retryPolicy?: RetryPolicy, configurable?: Record<string, unknown>, signal?: AbortSignal): Promise<{
|
|
12
|
+
task: PregelExecutableTask<N, C>;
|
|
13
|
+
result: unknown;
|
|
14
|
+
error: Error | undefined;
|
|
15
|
+
}>;
|
package/dist/pregel/retry.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { CHECKPOINT_NAMESPACE_SEPARATOR, Command } from "../constants.js";
|
|
1
|
+
import { CHECKPOINT_NAMESPACE_SEPARATOR, Command, CONFIG_KEY_RESUMING, } from "../constants.js";
|
|
2
2
|
import { getSubgraphsSeenSet, isGraphBubbleUp, isParentCommand, } from "../errors.js";
|
|
3
|
+
import { patchConfigurable } from "./utils/index.js";
|
|
3
4
|
export const DEFAULT_INITIAL_INTERVAL = 500;
|
|
4
5
|
export const DEFAULT_BACKOFF_FACTOR = 2;
|
|
5
6
|
export const DEFAULT_MAX_INTERVAL = 128000;
|
|
@@ -38,46 +39,9 @@ const DEFAULT_RETRY_ON_HANDLER = (error) => {
|
|
|
38
39
|
}
|
|
39
40
|
return true;
|
|
40
41
|
};
|
|
41
|
-
export async function
|
|
42
|
+
export async function _runWithRetry(
|
|
42
43
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
|
-
|
|
44
|
-
const { stepTimeout, retryPolicy } = options ?? {};
|
|
45
|
-
let signal = options?.signal;
|
|
46
|
-
// Start tasks
|
|
47
|
-
const executingTasksMap = Object.fromEntries(tasks.map((pregelTask) => {
|
|
48
|
-
return [pregelTask.id, _runWithRetry(pregelTask, retryPolicy)];
|
|
49
|
-
}));
|
|
50
|
-
if (stepTimeout && signal) {
|
|
51
|
-
if ("any" in AbortSignal) {
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
|
-
signal = AbortSignal.any([
|
|
54
|
-
signal,
|
|
55
|
-
AbortSignal.timeout(stepTimeout),
|
|
56
|
-
]);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
else if (stepTimeout) {
|
|
60
|
-
signal = AbortSignal.timeout(stepTimeout);
|
|
61
|
-
}
|
|
62
|
-
// Abort if signal is aborted
|
|
63
|
-
signal?.throwIfAborted();
|
|
64
|
-
let listener;
|
|
65
|
-
const signalPromise = new Promise((_resolve, reject) => {
|
|
66
|
-
listener = () => reject(new Error("Abort"));
|
|
67
|
-
signal?.addEventListener("abort", listener);
|
|
68
|
-
}).finally(() => signal?.removeEventListener("abort", listener));
|
|
69
|
-
while (Object.keys(executingTasksMap).length > 0) {
|
|
70
|
-
const settledTask = await Promise.race([
|
|
71
|
-
...Object.values(executingTasksMap),
|
|
72
|
-
signalPromise,
|
|
73
|
-
]);
|
|
74
|
-
yield settledTask;
|
|
75
|
-
delete executingTasksMap[settledTask.task.id];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
async function _runWithRetry(
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
80
|
-
pregelTask, retryPolicy) {
|
|
44
|
+
pregelTask, retryPolicy, configurable, signal) {
|
|
81
45
|
const resolvedRetryPolicy = pregelTask.retry_policy ?? retryPolicy;
|
|
82
46
|
let interval = resolvedRetryPolicy !== undefined
|
|
83
47
|
? resolvedRetryPolicy.initialInterval ?? DEFAULT_INITIAL_INTERVAL
|
|
@@ -85,28 +49,34 @@ pregelTask, retryPolicy) {
|
|
|
85
49
|
let attempts = 0;
|
|
86
50
|
let error;
|
|
87
51
|
let result;
|
|
52
|
+
let { config } = pregelTask;
|
|
53
|
+
if (configurable) {
|
|
54
|
+
config = patchConfigurable(config, configurable);
|
|
55
|
+
}
|
|
88
56
|
// eslint-disable-next-line no-constant-condition
|
|
89
57
|
while (true) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
58
|
+
if (signal?.aborted) {
|
|
59
|
+
// no need to throw here - we'll throw from the runner, instead.
|
|
60
|
+
// there's just no point in retrying if the user has requested an abort.
|
|
61
|
+
break;
|
|
93
62
|
}
|
|
63
|
+
// Clear any writes from previous attempts
|
|
64
|
+
pregelTask.writes.splice(0, pregelTask.writes.length);
|
|
94
65
|
error = undefined;
|
|
95
66
|
try {
|
|
96
|
-
result = await pregelTask.proc.invoke(pregelTask.input,
|
|
67
|
+
result = await pregelTask.proc.invoke(pregelTask.input, config);
|
|
97
68
|
break;
|
|
98
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
69
|
}
|
|
100
70
|
catch (e) {
|
|
101
71
|
error = e;
|
|
102
72
|
error.pregelTaskId = pregelTask.id;
|
|
103
73
|
if (isParentCommand(error)) {
|
|
104
|
-
const ns =
|
|
74
|
+
const ns = config?.configurable?.checkpoint_ns;
|
|
105
75
|
const cmd = error.command;
|
|
106
76
|
if (cmd.graph === ns) {
|
|
107
77
|
// this command is for the current graph, handle it
|
|
108
78
|
for (const writer of pregelTask.writers) {
|
|
109
|
-
await writer.invoke(cmd,
|
|
79
|
+
await writer.invoke(cmd, config);
|
|
110
80
|
}
|
|
111
81
|
break;
|
|
112
82
|
}
|
|
@@ -149,11 +119,13 @@ pregelTask, retryPolicy) {
|
|
|
149
119
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
120
|
error.constructor.unminifiable_name ??
|
|
151
121
|
error.constructor.name;
|
|
152
|
-
console.log(`Retrying task "${pregelTask.name}" after ${interval.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
|
|
122
|
+
console.log(`Retrying task "${String(pregelTask.name)}" after ${interval.toFixed(2)}ms (attempt ${attempts}) after ${errorName}: ${error}`);
|
|
123
|
+
// signal subgraphs to resume (if available)
|
|
124
|
+
config = patchConfigurable(config, { [CONFIG_KEY_RESUMING]: true });
|
|
153
125
|
}
|
|
154
126
|
finally {
|
|
155
127
|
// Clear checkpoint_ns seen (for subgraph detection)
|
|
156
|
-
const checkpointNs =
|
|
128
|
+
const checkpointNs = config?.configurable?.checkpoint_ns;
|
|
157
129
|
if (checkpointNs) {
|
|
158
130
|
getSubgraphsSeenSet().delete(checkpointNs);
|
|
159
131
|
}
|
|
@@ -162,6 +134,6 @@ pregelTask, retryPolicy) {
|
|
|
162
134
|
return {
|
|
163
135
|
task: pregelTask,
|
|
164
136
|
result,
|
|
165
|
-
error,
|
|
137
|
+
error: error,
|
|
166
138
|
};
|
|
167
139
|
}
|