async-lube 2.0.0 → 2.1.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 +34 -0
- package/README.md +1 -1
- package/docs/http.md +1 -1
- package/docs/reference.md +4 -2
- package/docs/tasks.md +19 -2
- package/package.json +4 -5
- package/public.d.ts +112 -0
- package/src/attempt.js +17 -7
- package/src/durable/context.js +107 -64
- package/src/durable/error.js +39 -15
- package/src/durable/index.js +18 -10
- package/src/durable/journal.js +29 -14
- package/src/durable/json.js +26 -9
- package/src/durable/lease.js +15 -5
- package/src/durable/persist.js +60 -22
- package/src/durable/run.js +103 -41
- package/src/durable/send.js +30 -13
- package/src/durable/serve.js +30 -24
- package/src/durable/state.js +28 -13
- package/src/durable/store.js +19 -10
- package/src/durable/watch.js +31 -11
- package/src/errors.js +9 -3
- package/src/flow/attempts.js +49 -29
- package/src/flow/builder.js +260 -161
- package/src/flow/compile.js +86 -66
- package/src/flow/graph.js +108 -42
- package/src/flow/index.js +13 -7
- package/src/flow/items.js +79 -46
- package/src/flow/nodes.js +267 -117
- package/src/flow/refs.js +27 -13
- package/src/flow/resources.js +9 -3
- package/src/flow/run.js +287 -114
- package/src/flow/streams.js +44 -19
- package/src/flow/subflows.js +93 -53
- package/src/http/config.js +11 -5
- package/src/http/index.js +25 -14
- package/src/http/refresh.js +29 -12
- package/src/http/request.js +246 -151
- package/src/http/response.js +105 -50
- package/src/http/retry.js +52 -27
- package/src/http/socket.js +220 -172
- package/src/http/sse.js +113 -74
- package/src/http/throttle.js +9 -4
- package/src/http/url.js +58 -35
- package/src/http/xhr.js +29 -24
- package/src/index.js +1 -0
- package/src/key.js +3 -5
- package/src/limiter.js +146 -65
- package/src/offload.js +116 -85
- package/src/offload_module.js +594 -0
- package/src/options.js +8 -4
- package/src/redial.js +129 -0
- package/src/signal.js +14 -4
- package/src/stream.js +353 -198
- package/types/attempt.d.ts.map +1 -1
- package/types/durable/index.d.ts.map +1 -1
- package/types/durable/state.d.ts.map +1 -1
- package/types/durable/store.d.ts.map +1 -1
- package/types/errors.d.ts.map +1 -1
- package/types/http/index.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/limiter.d.ts +5 -1
- package/types/limiter.d.ts.map +1 -1
- package/types/offload.d.ts +2 -16
- package/types/offload.d.ts.map +1 -1
- package/types/redial.d.ts +28 -0
- package/types/redial.d.ts.map +1 -0
- package/types/stream.d.ts +2 -0
- package/types/stream.d.ts.map +1 -1
package/src/flow/run.js
CHANGED
|
@@ -51,14 +51,22 @@ export function begin(c) {
|
|
|
51
51
|
clear_record(c, record)
|
|
52
52
|
touched.add(record.node.name)
|
|
53
53
|
} else {
|
|
54
|
-
for (const name of reset(c, record.node.name, true))
|
|
54
|
+
for (const name of reset(c, record.node.name, true)) {
|
|
55
|
+
touched.add(name)
|
|
56
|
+
}
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
|
-
for (const record of released)
|
|
58
|
-
|
|
59
|
+
for (const record of released) {
|
|
60
|
+
record.released = void 0
|
|
61
|
+
}
|
|
62
|
+
for (const name of touched) {
|
|
63
|
+
get_record(c, name).released = void 0
|
|
64
|
+
}
|
|
59
65
|
if (c.cycle.settled) {
|
|
60
66
|
c.cycle = create_cycle()
|
|
61
|
-
if (c.watched || c.streaming && c.observed)
|
|
67
|
+
if (c.watched || c.streaming && c.observed) {
|
|
68
|
+
c.cycle.promise.catch(noop)
|
|
69
|
+
}
|
|
62
70
|
c.run_status = "running"
|
|
63
71
|
c.steps = 0
|
|
64
72
|
start_pumps(c)
|
|
@@ -67,17 +75,23 @@ export function begin(c) {
|
|
|
67
75
|
c.run_options.signal
|
|
68
76
|
)
|
|
69
77
|
for (const record of c.records.values()) {
|
|
70
|
-
if (record.status == "cancelled")
|
|
78
|
+
if (record.status == "cancelled") {
|
|
79
|
+
prepare_restart(c, record)
|
|
80
|
+
}
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
|
-
for (const name of touched)
|
|
83
|
+
for (const name of touched) {
|
|
84
|
+
try_start(c, name)
|
|
85
|
+
}
|
|
74
86
|
}
|
|
75
87
|
/**
|
|
76
88
|
* @param {RunContext} c
|
|
77
89
|
* @returns {void}
|
|
78
90
|
*/
|
|
79
91
|
function check_complete(c) {
|
|
80
|
-
if (c.active_count || c.run_status != "running" || c.cycle.settled || c.releasing)
|
|
92
|
+
if (c.active_count || c.run_status != "running" || c.cycle.settled || c.releasing) {
|
|
93
|
+
return
|
|
94
|
+
}
|
|
81
95
|
/** @type {NodeRecord | undefined} */
|
|
82
96
|
let fatal
|
|
83
97
|
for (const record of c.records.values()) {
|
|
@@ -92,7 +106,9 @@ function check_complete(c) {
|
|
|
92
106
|
c.errors[fatal.node.name]
|
|
93
107
|
)
|
|
94
108
|
: void 0
|
|
95
|
-
if (failure)
|
|
109
|
+
if (failure) {
|
|
110
|
+
release_all(c, failure)
|
|
111
|
+
}
|
|
96
112
|
const holding = [ ...c.records.values() ].filter(
|
|
97
113
|
record => record.node.options.release && record.status == "done" && !record.released
|
|
98
114
|
)
|
|
@@ -115,7 +131,9 @@ function check_complete(c) {
|
|
|
115
131
|
c.releasing = false
|
|
116
132
|
for (const [ index, outcome ] of outcomes.entries()) {
|
|
117
133
|
const record = /** @type {NodeRecord} */(holding[index])/**/
|
|
118
|
-
if (outcome.status == "fulfilled" || record.released?.error !== void 0 || record.status != "done")
|
|
134
|
+
if (outcome.status == "fulfilled" || record.released?.error !== void 0 || record.status != "done") {
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
119
137
|
record.released = { error: outcome.reason }
|
|
120
138
|
c.errors[record.node.name] = outcome.reason
|
|
121
139
|
record.fatal = true
|
|
@@ -150,9 +168,14 @@ export function close_cycle(c, error, value) {
|
|
|
150
168
|
c.cycle.settled = true
|
|
151
169
|
c.unlink_signal()
|
|
152
170
|
c.unlink_signal = noop
|
|
153
|
-
if (error instanceof CancelError)
|
|
154
|
-
|
|
155
|
-
|
|
171
|
+
if (error instanceof CancelError) {
|
|
172
|
+
c.cycle.promise.catch(noop)
|
|
173
|
+
}
|
|
174
|
+
if (error) {
|
|
175
|
+
c.cycle.reject(error)
|
|
176
|
+
} else {
|
|
177
|
+
c.cycle.resolve(value)
|
|
178
|
+
}
|
|
156
179
|
schedule(c)
|
|
157
180
|
}
|
|
158
181
|
/**
|
|
@@ -176,10 +199,14 @@ function create_cycle() {
|
|
|
176
199
|
*/
|
|
177
200
|
export function defer(c, job) {
|
|
178
201
|
c.jobs.push(job)
|
|
179
|
-
if (c.flushing)
|
|
202
|
+
if (c.flushing) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
180
205
|
c.flushing = true
|
|
181
206
|
try {
|
|
182
|
-
for (const queued of c.jobs)
|
|
207
|
+
for (const queued of c.jobs) {
|
|
208
|
+
queued()
|
|
209
|
+
}
|
|
183
210
|
} finally {
|
|
184
211
|
c.jobs.length = 0
|
|
185
212
|
c.flushing = false
|
|
@@ -191,8 +218,10 @@ export function defer(c, job) {
|
|
|
191
218
|
*/
|
|
192
219
|
export function drain(c) {
|
|
193
220
|
while (c.running < c.concurrency && c.queue.length) {
|
|
194
|
-
|
|
195
|
-
|
|
221
|
+
start(
|
|
222
|
+
c,
|
|
223
|
+
/** @type {string} */(c.queue.shift())/**/
|
|
224
|
+
)
|
|
196
225
|
}
|
|
197
226
|
}
|
|
198
227
|
/**
|
|
@@ -206,7 +235,9 @@ function get_statuses(c) {
|
|
|
206
235
|
statuses[name] = record.status == "running" && record.sub_waiting && !record.sub_running && !record.delaying
|
|
207
236
|
? "waiting"
|
|
208
237
|
: record.status
|
|
209
|
-
if (record.status == "done" || record.status == "skipped")
|
|
238
|
+
if (record.status == "done" || record.status == "skipped") {
|
|
239
|
+
continue
|
|
240
|
+
}
|
|
210
241
|
for (const [ key, sub_run ] of record.sub_runs) {
|
|
211
242
|
const prefix = key ? name + "." + key : name
|
|
212
243
|
for (const [ sub_name, status ] of Object.entries(sub_run.nodes)) {
|
|
@@ -221,10 +252,14 @@ function get_statuses(c) {
|
|
|
221
252
|
* @returns {void}
|
|
222
253
|
*/
|
|
223
254
|
function notify(c) {
|
|
224
|
-
if (!c.waiters.length && !c.run_options[ON_CHANGE] && !c.subscribers.size)
|
|
255
|
+
if (!c.waiters.length && !c.run_options[ON_CHANGE] && !c.subscribers.size) {
|
|
256
|
+
return
|
|
257
|
+
}
|
|
225
258
|
const status = c.run.status
|
|
226
259
|
if (status != "running") {
|
|
227
|
-
for (const resolve of c.waiters.splice(0))
|
|
260
|
+
for (const resolve of c.waiters.splice(0)) {
|
|
261
|
+
resolve()
|
|
262
|
+
}
|
|
228
263
|
}
|
|
229
264
|
report(c, status)
|
|
230
265
|
publish(c)
|
|
@@ -234,7 +269,9 @@ function notify(c) {
|
|
|
234
269
|
* @returns {void}
|
|
235
270
|
*/
|
|
236
271
|
export function publish(c) {
|
|
237
|
-
if (!c.subscribers.size || c.notified_version == c.version)
|
|
272
|
+
if (!c.subscribers.size || c.notified_version == c.version) {
|
|
273
|
+
return
|
|
274
|
+
}
|
|
238
275
|
c.notified_version = c.version
|
|
239
276
|
for (const listener of [ ...c.subscribers ]) {
|
|
240
277
|
try {
|
|
@@ -249,9 +286,13 @@ export function publish(c) {
|
|
|
249
286
|
*/
|
|
250
287
|
export function report(c, status) {
|
|
251
288
|
const on_change = c.run_options[ON_CHANGE]
|
|
252
|
-
if (!on_change)
|
|
289
|
+
if (!on_change) {
|
|
290
|
+
return
|
|
291
|
+
}
|
|
253
292
|
const current = status ?? c.run.status
|
|
254
|
-
if (current == c.reported_status && c.reported_version == c.version)
|
|
293
|
+
if (current == c.reported_status && c.reported_version == c.version) {
|
|
294
|
+
return
|
|
295
|
+
}
|
|
255
296
|
c.reported_status = current
|
|
256
297
|
c.reported_version = c.version
|
|
257
298
|
on_change(current)
|
|
@@ -263,16 +304,24 @@ export function report(c, status) {
|
|
|
263
304
|
*/
|
|
264
305
|
function retry_failed(c, only_fatal) {
|
|
265
306
|
begin(c)
|
|
266
|
-
if (c.run_status != "running")
|
|
307
|
+
if (c.run_status != "running") {
|
|
308
|
+
return
|
|
309
|
+
}
|
|
267
310
|
/** @type {[string, ResumePlan, BacklogEntry[]][]} */
|
|
268
311
|
const plans = []
|
|
269
312
|
for (const [ name, record ] of c.records) {
|
|
270
|
-
if (only_fatal && !record.fatal)
|
|
313
|
+
if (only_fatal && !record.fatal) {
|
|
314
|
+
continue
|
|
315
|
+
}
|
|
271
316
|
const has_failed_items = !!(record.items ?? record.resume_items)?.some(item => item?.failed)
|
|
272
|
-
if (record.status != "failed" && !(record.status == "done" && (has_failed_items || failed_sub_keys(record).length)))
|
|
317
|
+
if (record.status != "failed" && !(record.status == "done" && (has_failed_items || failed_sub_keys(record).length))) {
|
|
318
|
+
continue
|
|
319
|
+
}
|
|
273
320
|
const plan = plan_retry(record)
|
|
274
321
|
if (record.args && !same_args(c, record)) {
|
|
275
|
-
if (record.status == "failed")
|
|
322
|
+
if (record.status == "failed") {
|
|
323
|
+
plan.items = void 0
|
|
324
|
+
}
|
|
276
325
|
plan.runs = void 0
|
|
277
326
|
plan.subs = void 0
|
|
278
327
|
}
|
|
@@ -288,16 +337,22 @@ function retry_failed(c, only_fatal) {
|
|
|
288
337
|
const reached = new Set()
|
|
289
338
|
for (const [ name ] of plans) {
|
|
290
339
|
for (const reset_name of reset(c, name, true, true)) {
|
|
291
|
-
if (reset_name != name)
|
|
340
|
+
if (reset_name != name) {
|
|
341
|
+
reached.add(reset_name)
|
|
342
|
+
}
|
|
292
343
|
}
|
|
293
344
|
}
|
|
294
345
|
for (const [ name, plan, backlog ] of plans) {
|
|
295
|
-
if (reached.has(name))
|
|
346
|
+
if (reached.has(name)) {
|
|
347
|
+
continue
|
|
348
|
+
}
|
|
296
349
|
const record = get_record(c, name)
|
|
297
350
|
plan_resume(record, plan)
|
|
298
351
|
record.backlog = backlog
|
|
299
352
|
}
|
|
300
|
-
for (const node_name of c.records.keys())
|
|
353
|
+
for (const node_name of c.records.keys()) {
|
|
354
|
+
try_start(c, node_name)
|
|
355
|
+
}
|
|
301
356
|
drain(c)
|
|
302
357
|
schedule(c)
|
|
303
358
|
}
|
|
@@ -307,14 +362,18 @@ function retry_failed(c, only_fatal) {
|
|
|
307
362
|
* @returns {unknown}
|
|
308
363
|
*/
|
|
309
364
|
function save_error(error, depth = 0) {
|
|
310
|
-
if (!(error instanceof Error))
|
|
365
|
+
if (!(error instanceof Error)) {
|
|
366
|
+
return error
|
|
367
|
+
}
|
|
311
368
|
/** @type {Record<string, unknown>} */
|
|
312
369
|
const saved = {
|
|
313
370
|
...error,
|
|
314
371
|
message: error.message,
|
|
315
372
|
name: error.name
|
|
316
373
|
}
|
|
317
|
-
if (error.cause !== void 0 && depth < 8)
|
|
374
|
+
if (error.cause !== void 0 && depth < 8) {
|
|
375
|
+
saved["cause"] = save_error(error.cause, depth + 1)
|
|
376
|
+
}
|
|
318
377
|
return saved
|
|
319
378
|
}
|
|
320
379
|
/**
|
|
@@ -322,7 +381,9 @@ function save_error(error, depth = 0) {
|
|
|
322
381
|
* @returns {void}
|
|
323
382
|
*/
|
|
324
383
|
export function schedule(c) {
|
|
325
|
-
if (c.scheduled)
|
|
384
|
+
if (c.scheduled) {
|
|
385
|
+
return
|
|
386
|
+
}
|
|
326
387
|
c.scheduled = true
|
|
327
388
|
queueMicrotask(
|
|
328
389
|
() => {
|
|
@@ -353,20 +414,28 @@ export function start_run(
|
|
|
353
414
|
const { edges, incoming } = program
|
|
354
415
|
c.edges = edges
|
|
355
416
|
c.incoming = incoming
|
|
356
|
-
if (run_options.id != null && !(typeof run_options.id == "string" && run_options.id))
|
|
357
|
-
|
|
358
|
-
|
|
417
|
+
if (run_options.id != null && !(typeof run_options.id == "string" && run_options.id)) {
|
|
418
|
+
throw TypeError(
|
|
419
|
+
"The id of a run must be a non-empty string"
|
|
420
|
+
)
|
|
421
|
+
}
|
|
359
422
|
const { snapshot } = run_options
|
|
360
423
|
if (snapshot != null) {
|
|
361
|
-
if (typeof snapshot != "object" || !snapshot.nodes || typeof snapshot.nodes != "object")
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
)
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
424
|
+
if (typeof snapshot != "object" || !snapshot.nodes || typeof snapshot.nodes != "object") {
|
|
425
|
+
throw TypeError(
|
|
426
|
+
"Invalid flow snapshot: pass the result of run.snapshot()"
|
|
427
|
+
)
|
|
428
|
+
}
|
|
429
|
+
if (snapshot.version !== 1) {
|
|
430
|
+
throw TypeError(
|
|
431
|
+
`Unknown flow snapshot version ${String(snapshot.version)}: pass the result of run.snapshot()`
|
|
432
|
+
)
|
|
433
|
+
}
|
|
434
|
+
if (run_options.id != null && snapshot.id != null && snapshot.id !== run_options.id) {
|
|
435
|
+
throw TypeError(
|
|
436
|
+
`The id "${run_options.id}" of the run is not the id "${snapshot.id}" of its snapshot`
|
|
437
|
+
)
|
|
438
|
+
}
|
|
370
439
|
}
|
|
371
440
|
const run_id = snapshot?.id ?? run_options.id ?? run_options[RUN_ID] ?? random_key()
|
|
372
441
|
c.run_id = run_id
|
|
@@ -498,12 +567,16 @@ export function start_run(
|
|
|
498
567
|
if (snapshot != null) {
|
|
499
568
|
for (const [ name, data ] of Object.entries(snapshot.nodes)) {
|
|
500
569
|
const record = records.get(name)
|
|
501
|
-
if (!record)
|
|
502
|
-
|
|
503
|
-
|
|
570
|
+
if (!record) {
|
|
571
|
+
throw Error(
|
|
572
|
+
`The snapshot has unknown flow node "${name}"`
|
|
573
|
+
)
|
|
574
|
+
}
|
|
504
575
|
record.abandoned = !!data.abandoned
|
|
505
576
|
record.activated = data.activated
|
|
506
|
-
for (const source of data.activators ?? (data.activated && incoming.has(name) ? [ "*" ] : []))
|
|
577
|
+
for (const source of data.activators ?? (data.activated && incoming.has(name) ? [ "*" ] : [])) {
|
|
578
|
+
record.activators.add(source)
|
|
579
|
+
}
|
|
507
580
|
record.backlog = data.backlog ?? []
|
|
508
581
|
record.backlog_head = 0
|
|
509
582
|
record.buffer = data.buffer
|
|
@@ -517,45 +590,61 @@ export function start_run(
|
|
|
517
590
|
)
|
|
518
591
|
}
|
|
519
592
|
record.resume_subs = data.subs
|
|
520
|
-
if (data.sends)
|
|
593
|
+
if (data.sends) {
|
|
594
|
+
record.sends = new Map(Object.entries(data.sends))
|
|
595
|
+
}
|
|
521
596
|
record.resume_runs = data.runs
|
|
522
597
|
record.resume_deadline = data.deadline
|
|
523
598
|
record.serial = data.serial ?? 0
|
|
524
599
|
record.fatal = data.status == "failed" && !!data.fatal
|
|
525
600
|
record.holding = data.status == "failed" && !data.fatal && !!data.queued
|
|
526
|
-
if (record.fatal)
|
|
601
|
+
if (record.fatal) {
|
|
602
|
+
resumes_failure = true
|
|
603
|
+
}
|
|
527
604
|
set_status(c, record, data.status)
|
|
528
605
|
if (data.status == "done") {
|
|
529
606
|
record.items = data.items
|
|
530
607
|
record.result = data.items ? data.items.map(item => item?.value) : data.result
|
|
531
608
|
results[name] = record.result
|
|
532
|
-
} else
|
|
609
|
+
} else {
|
|
610
|
+
record.resume_items = data.items
|
|
611
|
+
}
|
|
533
612
|
}
|
|
534
613
|
Object.assign(errors, snapshot.errors)
|
|
535
614
|
for (const record of records.values()) {
|
|
536
615
|
const { arrive, deps } = record.node
|
|
537
616
|
if (record.backlog.length && deps.some(
|
|
538
617
|
dep => arrive?.[dep] != "queue" && !settled_statuses.has(get_record(c, dep).status)
|
|
539
|
-
))
|
|
618
|
+
)) {
|
|
619
|
+
record.retrigger = true
|
|
620
|
+
}
|
|
540
621
|
}
|
|
541
622
|
}
|
|
542
623
|
/** @type {FlowRunner} */
|
|
543
624
|
const run = {
|
|
544
625
|
cancel(reason) {
|
|
545
626
|
stop_pumps(c)
|
|
546
|
-
for (const source of streams.values())
|
|
627
|
+
for (const source of streams.values()) {
|
|
628
|
+
source.close()
|
|
629
|
+
}
|
|
547
630
|
streams.clear()
|
|
548
|
-
if (c.run_status != "running")
|
|
631
|
+
if (c.run_status != "running") {
|
|
632
|
+
return
|
|
633
|
+
}
|
|
549
634
|
const error = new CancelError(
|
|
550
635
|
reason ?? "The flow was cancelled"
|
|
551
636
|
)
|
|
552
637
|
release_all(c, error)
|
|
553
638
|
stop_all(c, "cancelled", error)
|
|
554
639
|
c.run_status = "cancelled"
|
|
555
|
-
if (!c.cycle.settled)
|
|
640
|
+
if (!c.cycle.settled) {
|
|
641
|
+
close_cycle(c, error, void 0)
|
|
642
|
+
}
|
|
556
643
|
},
|
|
557
644
|
get errors() {
|
|
558
|
-
if (errors_cache && errors_version == c.version)
|
|
645
|
+
if (errors_cache && errors_version == c.version) {
|
|
646
|
+
return errors_cache
|
|
647
|
+
}
|
|
559
648
|
/** @type {Record<string, unknown>} */
|
|
560
649
|
const all = { ...errors }
|
|
561
650
|
for (const [ name, record ] of records) {
|
|
@@ -571,7 +660,9 @@ export function start_run(
|
|
|
571
660
|
]
|
|
572
661
|
)
|
|
573
662
|
for (const [ key, sub_errors ] of subs) {
|
|
574
|
-
for (const [ sub_key, error ] of Object.entries(sub_errors))
|
|
663
|
+
for (const [ sub_key, error ] of Object.entries(sub_errors)) {
|
|
664
|
+
all[(key ? name + "." + key : name) + "." + sub_key] = error
|
|
665
|
+
}
|
|
575
666
|
}
|
|
576
667
|
}
|
|
577
668
|
errors_cache = all
|
|
@@ -581,9 +672,15 @@ export function start_run(
|
|
|
581
672
|
[STOP]: stop_pumps.bind(void 0, c),
|
|
582
673
|
[FAILURES]() {
|
|
583
674
|
for (const record of records.values()) {
|
|
584
|
-
if (record.status == "failed" && !record.fatal)
|
|
585
|
-
|
|
586
|
-
|
|
675
|
+
if (record.status == "failed" && !record.fatal) {
|
|
676
|
+
return true
|
|
677
|
+
}
|
|
678
|
+
if ((record.items ?? record.resume_items)?.some(item => item?.failed)) {
|
|
679
|
+
return true
|
|
680
|
+
}
|
|
681
|
+
if (failed_sub_keys(record).length) {
|
|
682
|
+
return true
|
|
683
|
+
}
|
|
587
684
|
}
|
|
588
685
|
return false
|
|
589
686
|
},
|
|
@@ -599,7 +696,9 @@ export function start_run(
|
|
|
599
696
|
},
|
|
600
697
|
idle() {
|
|
601
698
|
watch(c)
|
|
602
|
-
if (run.status != "running")
|
|
699
|
+
if (run.status != "running") {
|
|
700
|
+
return Promise.resolve()
|
|
701
|
+
}
|
|
603
702
|
return /** @type {Promise<void>} */(new Promise(
|
|
604
703
|
resolve => waiters.push(() => resolve())
|
|
605
704
|
))/**/
|
|
@@ -618,7 +717,9 @@ export function start_run(
|
|
|
618
717
|
}
|
|
619
718
|
const record = get_record(c, name_or_throw(c, target))
|
|
620
719
|
let queued = active_statuses.has(record.status) ? 1 : 0
|
|
621
|
-
for (const waiting of record.queued?.values() ?? [])
|
|
720
|
+
for (const waiting of record.queued?.values() ?? []) {
|
|
721
|
+
queued = Math.max(queued, waiting.length)
|
|
722
|
+
}
|
|
622
723
|
return record.backlog.length - record.backlog_head + queued - (record.holding ? 1 : 0)
|
|
623
724
|
},
|
|
624
725
|
reload(target) {
|
|
@@ -629,15 +730,21 @@ export function start_run(
|
|
|
629
730
|
}
|
|
630
731
|
const name = target == null ? void 0 : name_or_throw(c, target)
|
|
631
732
|
begin(c)
|
|
632
|
-
if (c.run_status != "running")
|
|
733
|
+
if (c.run_status != "running") {
|
|
734
|
+
return
|
|
735
|
+
}
|
|
633
736
|
if (name == null) {
|
|
634
737
|
for (const record of records.values()) {
|
|
635
738
|
clear_record(c, record)
|
|
636
739
|
record.activators.clear()
|
|
637
740
|
record.activated = !incoming.has(record.node.name)
|
|
638
741
|
}
|
|
639
|
-
} else
|
|
640
|
-
|
|
742
|
+
} else {
|
|
743
|
+
enter(c, [ name ], "*", true)
|
|
744
|
+
}
|
|
745
|
+
for (const node_name of records.keys()) {
|
|
746
|
+
try_start(c, node_name)
|
|
747
|
+
}
|
|
641
748
|
drain(c)
|
|
642
749
|
schedule(c)
|
|
643
750
|
},
|
|
@@ -658,41 +765,57 @@ export function start_run(
|
|
|
658
765
|
}
|
|
659
766
|
const name = name_or_throw(c, target)
|
|
660
767
|
const record = get_record(c, name)
|
|
661
|
-
if (record.node.kind != "input")
|
|
662
|
-
|
|
663
|
-
|
|
768
|
+
if (record.node.kind != "input") {
|
|
769
|
+
throw Error(
|
|
770
|
+
`Flow node "${name}" is not an input`
|
|
771
|
+
)
|
|
772
|
+
}
|
|
664
773
|
if (record.status == "waiting" && c.run_status == "running") {
|
|
665
774
|
settle(c, name, "done", value)
|
|
666
775
|
return
|
|
667
776
|
}
|
|
668
|
-
if (record.abandoned)
|
|
777
|
+
if (record.abandoned) {
|
|
778
|
+
return
|
|
779
|
+
}
|
|
669
780
|
record.buffer = { value }
|
|
670
781
|
if (settled_statuses.has(record.status) || record.status == "cancelled") {
|
|
671
782
|
begin(c)
|
|
672
|
-
if (c.run_status != "running")
|
|
783
|
+
if (c.run_status != "running") {
|
|
784
|
+
return
|
|
785
|
+
}
|
|
673
786
|
enter(c, [ name ], "*")
|
|
674
|
-
for (const node_name of records.keys())
|
|
787
|
+
for (const node_name of records.keys()) {
|
|
788
|
+
try_start(c, node_name)
|
|
789
|
+
}
|
|
675
790
|
drain(c)
|
|
676
791
|
schedule(c)
|
|
677
792
|
}
|
|
678
793
|
},
|
|
679
794
|
snapshot() {
|
|
680
|
-
if (!run_options[ON_CHANGE])
|
|
795
|
+
if (!run_options[ON_CHANGE]) {
|
|
796
|
+
check_snapshot_names(program, "")
|
|
797
|
+
}
|
|
681
798
|
/** @type {Record<string, SavedNode>} */
|
|
682
799
|
const snapshot_nodes = {}
|
|
683
800
|
/** @type {Set<string>} */
|
|
684
801
|
const held = new Set()
|
|
685
802
|
for (const [ name, record ] of records) {
|
|
686
|
-
if (record.node.options.release && record.status == "done" && !record.released)
|
|
803
|
+
if (record.node.options.release && record.status == "done" && !record.released) {
|
|
804
|
+
held.add(name)
|
|
805
|
+
}
|
|
687
806
|
}
|
|
688
807
|
const redone = new Set(held)
|
|
689
808
|
for (const name of redone) {
|
|
690
809
|
for (const dependent of get_record(c, name).node.dependents) {
|
|
691
|
-
if (get_record(c, dependent).status == "done")
|
|
810
|
+
if (get_record(c, dependent).status == "done") {
|
|
811
|
+
redone.add(dependent)
|
|
812
|
+
}
|
|
692
813
|
}
|
|
693
814
|
}
|
|
694
815
|
for (const [ name, record ] of records) {
|
|
695
|
-
if (record.node.options.release && record.status == "done")
|
|
816
|
+
if (record.node.options.release && record.status == "done") {
|
|
817
|
+
redone.add(name)
|
|
818
|
+
}
|
|
696
819
|
}
|
|
697
820
|
for (const [ name, record ] of records) {
|
|
698
821
|
const { status } = record
|
|
@@ -702,22 +825,42 @@ export function start_run(
|
|
|
702
825
|
activated: record.activated,
|
|
703
826
|
status: is_kept ? /** @type {"done" | "failed" | "skipped"} */(status)/**/ : "idle"
|
|
704
827
|
}
|
|
705
|
-
if (record.abandoned)
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
if (
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
if (record.
|
|
712
|
-
|
|
713
|
-
|
|
828
|
+
if (record.abandoned) {
|
|
829
|
+
data.abandoned = true
|
|
830
|
+
}
|
|
831
|
+
if (record.activators.size) {
|
|
832
|
+
data.activators = [ ...record.activators ]
|
|
833
|
+
}
|
|
834
|
+
if (record.fatal && status == "failed") {
|
|
835
|
+
data.fatal = true
|
|
836
|
+
}
|
|
837
|
+
if (status == "done") {
|
|
838
|
+
data.result = record.result
|
|
839
|
+
}
|
|
840
|
+
if (record.previous !== void 0) {
|
|
841
|
+
data.previous = record.previous
|
|
842
|
+
}
|
|
843
|
+
if (record.buffer) {
|
|
844
|
+
data.buffer = { value: record.buffer.value }
|
|
845
|
+
}
|
|
846
|
+
if (record.sends?.size) {
|
|
847
|
+
data.sends = Object.fromEntries(record.sends)
|
|
848
|
+
}
|
|
849
|
+
if (status == "waiting" && record.deadline != null) {
|
|
850
|
+
data.deadline = record.deadline
|
|
851
|
+
}
|
|
852
|
+
if (record.serial) {
|
|
853
|
+
data.serial = record.serial
|
|
854
|
+
}
|
|
714
855
|
const is_stale = status == "done"
|
|
715
856
|
? redone.has(name)
|
|
716
857
|
: !(record.node.options.overlap == "queue" && active_statuses.has(status)) && !!record.args && (!same_args(c, record) || record.node.deps.some(dep => redone.has(dep)))
|
|
717
858
|
const is_moved = is_stale || status == "done" && !!(record.runs.size || record.resume_runs || record.sub_runs.size || record.resume_subs) && !!record.args && !same_args(c, record)
|
|
718
859
|
if (!is_moved && (record.runs.size || record.resume_runs)) {
|
|
719
860
|
data.runs = { ...record.resume_runs }
|
|
720
|
-
for (const [ unit, run_state ] of record.runs)
|
|
861
|
+
for (const [ unit, run_state ] of record.runs) {
|
|
862
|
+
data.runs[unit] = save_run(run_state)
|
|
863
|
+
}
|
|
721
864
|
} else if (held.has(name) && same_args(c, record) && !record.node.deps.some(dep => redone.has(dep))) {
|
|
722
865
|
data.runs = {
|
|
723
866
|
"": {
|
|
@@ -728,7 +871,10 @@ export function start_run(
|
|
|
728
871
|
}
|
|
729
872
|
}
|
|
730
873
|
for (const [ dep, values ] of record.queued ?? []) {
|
|
731
|
-
if (values.length)
|
|
874
|
+
if (values.length) {
|
|
875
|
+
const queued = data.queued ??= {}
|
|
876
|
+
queued[dep] = [ ...values ]
|
|
877
|
+
}
|
|
732
878
|
}
|
|
733
879
|
const in_flight = record.node.options.overlap == "queue" && active_statuses.has(status) && record.args
|
|
734
880
|
const backlog = in_flight
|
|
@@ -741,27 +887,34 @@ export function start_run(
|
|
|
741
887
|
...record.backlog.slice(record.backlog_head)
|
|
742
888
|
]
|
|
743
889
|
: record.backlog.slice(record.backlog_head)
|
|
744
|
-
if (backlog.length)
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
890
|
+
if (backlog.length) {
|
|
891
|
+
data.backlog = backlog.map(
|
|
892
|
+
entry => entry.resume
|
|
893
|
+
? {
|
|
894
|
+
args: [ ...entry.args ],
|
|
895
|
+
resume: true,
|
|
896
|
+
skipped: entry.skipped
|
|
897
|
+
}
|
|
898
|
+
: {
|
|
899
|
+
args: [ ...entry.args ],
|
|
900
|
+
skipped: entry.skipped
|
|
901
|
+
}
|
|
902
|
+
)
|
|
903
|
+
}
|
|
756
904
|
const items = record.items ?? record.resume_items
|
|
757
905
|
const has_failed_items = !!items?.some(item => item?.failed)
|
|
758
906
|
if (!is_stale && (!is_kept || status == "failed" || has_failed_items || failed_sub_keys(record).length)) {
|
|
759
|
-
if (items)
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
907
|
+
if (items) {
|
|
908
|
+
data.items = Array.from(
|
|
909
|
+
{ length: items.length },
|
|
910
|
+
(_, index) => items[index] ?? null
|
|
911
|
+
)
|
|
912
|
+
}
|
|
913
|
+
if (!is_moved && record.sub_runs.size) {
|
|
914
|
+
data.subs = snapshot_subs(record)
|
|
915
|
+
} else if (!is_moved && record.resume_subs) {
|
|
916
|
+
data.subs = record.resume_subs
|
|
917
|
+
}
|
|
765
918
|
}
|
|
766
919
|
snapshot_nodes[name] = data
|
|
767
920
|
}
|
|
@@ -770,11 +923,15 @@ export function start_run(
|
|
|
770
923
|
for (const [ key, error ] of Object.entries(errors)) {
|
|
771
924
|
const dot = key.indexOf(".")
|
|
772
925
|
const data = snapshot_nodes[dot < 0 ? key : key.slice(0, dot)]
|
|
773
|
-
if (!data)
|
|
926
|
+
if (!data) {
|
|
927
|
+
continue
|
|
928
|
+
}
|
|
774
929
|
const is_kept = dot < 0 || !data.items || data.fatal
|
|
775
930
|
? data.status != "idle"
|
|
776
931
|
: data.items[Number(key.slice(dot + 1))] != null
|
|
777
|
-
if (is_kept)
|
|
932
|
+
if (is_kept) {
|
|
933
|
+
snapshot_errors[key] = save_error(error)
|
|
934
|
+
}
|
|
778
935
|
}
|
|
779
936
|
return {
|
|
780
937
|
errors: snapshot_errors,
|
|
@@ -787,15 +944,23 @@ export function start_run(
|
|
|
787
944
|
return state
|
|
788
945
|
},
|
|
789
946
|
get status() {
|
|
790
|
-
if (c.run_status != "running")
|
|
947
|
+
if (c.run_status != "running") {
|
|
948
|
+
return c.run_status
|
|
949
|
+
}
|
|
791
950
|
let waiting = false
|
|
792
951
|
for (const record of records.values()) {
|
|
793
|
-
if (record.delaying)
|
|
952
|
+
if (record.delaying) {
|
|
953
|
+
return "running"
|
|
954
|
+
}
|
|
794
955
|
if (record.status == "running") {
|
|
795
|
-
if (record.sub_running || !record.sub_waiting)
|
|
956
|
+
if (record.sub_running || !record.sub_waiting) {
|
|
957
|
+
return "running"
|
|
958
|
+
}
|
|
959
|
+
waiting = true
|
|
960
|
+
}
|
|
961
|
+
if (record.status == "waiting") {
|
|
796
962
|
waiting = true
|
|
797
963
|
}
|
|
798
|
-
if (record.status == "waiting") waiting = true
|
|
799
964
|
}
|
|
800
965
|
return waiting ? "waiting" : "running"
|
|
801
966
|
},
|
|
@@ -816,7 +981,9 @@ export function start_run(
|
|
|
816
981
|
}
|
|
817
982
|
},
|
|
818
983
|
then(on_fulfilled, on_rejected) {
|
|
819
|
-
if (on_rejected)
|
|
984
|
+
if (on_rejected) {
|
|
985
|
+
c.observed = true
|
|
986
|
+
}
|
|
820
987
|
return c.cycle.promise.then(on_fulfilled, on_rejected)
|
|
821
988
|
}
|
|
822
989
|
}
|
|
@@ -860,8 +1027,12 @@ export function start_run(
|
|
|
860
1027
|
signal_target,
|
|
861
1028
|
run_options.signal
|
|
862
1029
|
)
|
|
863
|
-
if (resumes_failure)
|
|
864
|
-
|
|
1030
|
+
if (resumes_failure) {
|
|
1031
|
+
retry_failed(c, true)
|
|
1032
|
+
}
|
|
1033
|
+
for (const name of records.keys()) {
|
|
1034
|
+
try_start(c, name)
|
|
1035
|
+
}
|
|
865
1036
|
start_pumps(c)
|
|
866
1037
|
schedule(c)
|
|
867
1038
|
return run
|
|
@@ -871,7 +1042,9 @@ export function start_run(
|
|
|
871
1042
|
* @returns {void}
|
|
872
1043
|
*/
|
|
873
1044
|
function watch(c) {
|
|
874
|
-
if (c.watched)
|
|
1045
|
+
if (c.watched) {
|
|
1046
|
+
return
|
|
1047
|
+
}
|
|
875
1048
|
c.watched = true
|
|
876
1049
|
c.cycle.promise.catch(noop)
|
|
877
1050
|
}
|