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/durable/error.js
CHANGED
|
@@ -33,14 +33,25 @@ const error_types = new Map(
|
|
|
33
33
|
export function error_from(info) {
|
|
34
34
|
const error = /** @type {Error & Record<string, unknown>} */(Error(info.message))/**/
|
|
35
35
|
const type = error_types.get(info.name)
|
|
36
|
-
if (type)
|
|
37
|
-
|
|
36
|
+
if (type) {
|
|
37
|
+
Object.setPrototypeOf(error, type.prototype)
|
|
38
|
+
}
|
|
39
|
+
if (error.name != info.name) {
|
|
40
|
+
error.name = info.name
|
|
41
|
+
}
|
|
38
42
|
for (const key of Object.keys(info)) {
|
|
39
|
-
if (key != "cause" && key != "message" && key != "name")
|
|
43
|
+
if (key != "cause" && key != "message" && key != "name") {
|
|
44
|
+
error[key] = copy(info[key])
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (info.cause) {
|
|
48
|
+
error.cause = error_from(info.cause)
|
|
49
|
+
} else if (info.name == "CancelError") {
|
|
50
|
+
error.cause = info.message
|
|
51
|
+
}
|
|
52
|
+
if (info.name != "HttpError") {
|
|
53
|
+
return error
|
|
40
54
|
}
|
|
41
|
-
if (info.cause) error.cause = error_from(info.cause)
|
|
42
|
-
else if (info.name == "CancelError") error.cause = info.message
|
|
43
|
-
if (info.name != "HttpError") return error
|
|
44
55
|
const { headers: pairs, status, statusText } = info
|
|
45
56
|
const headers = new Headers(
|
|
46
57
|
/** @type {[string, string][]} */(pairs ?? [])/**/
|
|
@@ -66,7 +77,9 @@ export function error_from(info) {
|
|
|
66
77
|
* @returns {unknown}
|
|
67
78
|
*/
|
|
68
79
|
export function error_of(saved) {
|
|
69
|
-
if (saved.status == "cancelled" && !saved.error)
|
|
80
|
+
if (saved.status == "cancelled" && !saved.error) {
|
|
81
|
+
return new CancelError("Cancelled")
|
|
82
|
+
}
|
|
70
83
|
return error_from(
|
|
71
84
|
saved.error ?? {
|
|
72
85
|
message: "The run failed",
|
|
@@ -80,9 +93,11 @@ export function error_of(saved) {
|
|
|
80
93
|
* @returns {SavedError}
|
|
81
94
|
*/
|
|
82
95
|
export function saved_error(error, seen = []) {
|
|
83
|
-
if (!(error instanceof Error))
|
|
84
|
-
|
|
85
|
-
|
|
96
|
+
if (!(error instanceof Error)) {
|
|
97
|
+
return {
|
|
98
|
+
message: String(error),
|
|
99
|
+
name: "Error"
|
|
100
|
+
}
|
|
86
101
|
}
|
|
87
102
|
seen.push(error)
|
|
88
103
|
/** @type {SavedError} */
|
|
@@ -93,12 +108,19 @@ export function saved_error(error, seen = []) {
|
|
|
93
108
|
const fields = /** @type {Error & Record<string, unknown>} */(error)/**/
|
|
94
109
|
for (const key of Object.keys(error)) {
|
|
95
110
|
const value = fields[key]
|
|
96
|
-
if (key == "cause" || key == "message" || key == "name" || key == "stack" || value === void 0)
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
if (key == "cause" || key == "message" || key == "name" || key == "stack" || value === void 0) {
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
if (value instanceof Headers) {
|
|
115
|
+
saved[key] = [ ...value ]
|
|
116
|
+
} else if (!json_problem(value)) {
|
|
117
|
+
saved[key] = copy(value)
|
|
118
|
+
}
|
|
99
119
|
}
|
|
100
120
|
const { cause } = error
|
|
101
|
-
if (cause instanceof Error && !seen.includes(cause))
|
|
121
|
+
if (cause instanceof Error && !seen.includes(cause)) {
|
|
122
|
+
saved.cause = saved_error(cause, seen)
|
|
123
|
+
}
|
|
102
124
|
return saved
|
|
103
125
|
}
|
|
104
126
|
/**
|
|
@@ -120,6 +142,8 @@ export function store_error(error) {
|
|
|
120
142
|
export function timeout_error(entry, wait_options) {
|
|
121
143
|
const { timeout, until } = wait_options
|
|
122
144
|
const error = new TimeoutError(timeout ?? 0)
|
|
123
|
-
if (until != null && entry.until == until)
|
|
145
|
+
if (until != null && entry.until == until) {
|
|
146
|
+
error.message = `Timed out at ${new Date(until).toISOString()}`
|
|
147
|
+
}
|
|
124
148
|
return error
|
|
125
149
|
}
|
package/src/durable/index.js
CHANGED
|
@@ -47,15 +47,21 @@ export function durable(store, fn, options = {}) {
|
|
|
47
47
|
const idle_ms = options.idle ?? 1000
|
|
48
48
|
const lease_ms = options.lease ?? 30000
|
|
49
49
|
const poll_ms = options.poll ?? 500
|
|
50
|
-
if (!(typeof idle_ms == "number" && idle_ms >= 0))
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
if (!(typeof idle_ms == "number" && idle_ms >= 0)) {
|
|
51
|
+
throw TypeError(
|
|
52
|
+
"The idle of durable() must be a non-negative number of milliseconds"
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
if (!(Number.isFinite(lease_ms) && lease_ms > 0)) {
|
|
56
|
+
throw TypeError(
|
|
57
|
+
"The lease of durable() must be a positive number of milliseconds"
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
if (!(Number.isFinite(poll_ms) && poll_ms > 0)) {
|
|
61
|
+
throw TypeError(
|
|
62
|
+
"The poll of durable() must be a positive number of milliseconds"
|
|
63
|
+
)
|
|
64
|
+
}
|
|
59
65
|
/** @type {DurableWorker} */
|
|
60
66
|
const d = {
|
|
61
67
|
fn: /** @type {DurableWorker["fn"]} */(fn)/**/,
|
|
@@ -101,7 +107,9 @@ export function durable(store, fn, options = {}) {
|
|
|
101
107
|
) => enter(d, key, input, "start"),
|
|
102
108
|
stop() {
|
|
103
109
|
d.halted = true
|
|
104
|
-
for (const stop of [ ...d.stoppers ])
|
|
110
|
+
for (const stop of [ ...d.stoppers ]) {
|
|
111
|
+
stop()
|
|
112
|
+
}
|
|
105
113
|
for (const key of [ ...d.watchers.keys() ]) {
|
|
106
114
|
settle(
|
|
107
115
|
d,
|
package/src/durable/journal.js
CHANGED
|
@@ -11,9 +11,11 @@ export function entry_of(execution, name, type) {
|
|
|
11
11
|
const { journal } = execution.saved
|
|
12
12
|
const entry = journal[index]
|
|
13
13
|
if (entry) {
|
|
14
|
-
if (entry.name != name || entry.type != type)
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
if (entry.name != name || entry.type != type) {
|
|
15
|
+
throw Error(
|
|
16
|
+
`The run "${execution.key}" changed: step ${index + 1} was "${entry.name}", now "${name}"`
|
|
17
|
+
)
|
|
18
|
+
}
|
|
17
19
|
return entry
|
|
18
20
|
}
|
|
19
21
|
/** @type {JournalEntry} */
|
|
@@ -58,18 +60,25 @@ export function rewind(execution, error) {
|
|
|
58
60
|
seen.add(cause)
|
|
59
61
|
const failure = execution.failures.get(cause)
|
|
60
62
|
if (failure) {
|
|
61
|
-
if (execution.cursor > failure.reached)
|
|
63
|
+
if (execution.cursor > failure.reached) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
62
66
|
const { saved } = execution
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (later.type != "wait" || !later.done || later.timed_out)
|
|
67
|
+
for (const later of saved.journal.splice(
|
|
68
|
+
saved.journal.indexOf(failure.entry)
|
|
69
|
+
).reverse()) {
|
|
70
|
+
if (later.type != "wait" || !later.done || later.timed_out) {
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
67
73
|
const events = saved.events ??= {}
|
|
68
|
-
|
|
74
|
+
const queue = events[later.name] ??= []
|
|
75
|
+
queue.unshift({ at: 0, value: later.value })
|
|
69
76
|
}
|
|
70
77
|
return
|
|
71
78
|
}
|
|
72
|
-
if (!(cause instanceof Error))
|
|
79
|
+
if (!(cause instanceof Error)) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
73
82
|
cause = cause.cause
|
|
74
83
|
}
|
|
75
84
|
}
|
|
@@ -81,7 +90,9 @@ export function rewind(execution, error) {
|
|
|
81
90
|
*/
|
|
82
91
|
export function take_waiter(execution, name, at) {
|
|
83
92
|
const list = execution.waiters.get(name)
|
|
84
|
-
if (!list)
|
|
93
|
+
if (!list) {
|
|
94
|
+
return
|
|
95
|
+
}
|
|
85
96
|
const index = list.findIndex(
|
|
86
97
|
waiter => waiter.entry.until == null || at <= waiter.entry.until
|
|
87
98
|
)
|
|
@@ -93,8 +104,12 @@ export function take_waiter(execution, name, at) {
|
|
|
93
104
|
* @returns {void}
|
|
94
105
|
*/
|
|
95
106
|
export function unblock(execution, waiter) {
|
|
96
|
-
if (!waiter.block)
|
|
97
|
-
|
|
98
|
-
|
|
107
|
+
if (!waiter.block) {
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
execution.blocked.splice(
|
|
111
|
+
execution.blocked.indexOf(waiter.block),
|
|
112
|
+
1
|
|
113
|
+
)
|
|
99
114
|
waiter.block = void 0
|
|
100
115
|
}
|
package/src/durable/json.js
CHANGED
|
@@ -13,13 +13,19 @@ export function copy(value) {
|
|
|
13
13
|
* @returns {string | undefined}
|
|
14
14
|
*/
|
|
15
15
|
export function json_problem(value) {
|
|
16
|
-
if (value === void 0)
|
|
16
|
+
if (value === void 0) {
|
|
17
|
+
return
|
|
18
|
+
}
|
|
17
19
|
/** @type {(number | string)[]} */
|
|
18
20
|
const path = []
|
|
19
21
|
const problem = json_problem_at(value, path, [])
|
|
20
|
-
if (!problem)
|
|
22
|
+
if (!problem) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
21
25
|
let at = ""
|
|
22
|
-
for (const part of path)
|
|
26
|
+
for (const part of path) {
|
|
27
|
+
at += typeof part == "number" ? `[${part}]` : `.${part}`
|
|
28
|
+
}
|
|
23
29
|
return at ? `${problem} at ${at}` : problem
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
@@ -38,20 +44,27 @@ function json_problem_at(value, path, parents) {
|
|
|
38
44
|
case "number": return Number.isFinite(value) ? void 0 : String(value)
|
|
39
45
|
case "undefined": return "undefined"
|
|
40
46
|
}
|
|
41
|
-
if (value === null)
|
|
42
|
-
|
|
47
|
+
if (value === null) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
if (parents.includes(value)) {
|
|
51
|
+
return "a circular reference"
|
|
52
|
+
}
|
|
43
53
|
if (Array.isArray(value)) {
|
|
44
54
|
parents.push(value)
|
|
45
55
|
for (let index = 0; index < value.length; index++) {
|
|
46
56
|
path.push(index)
|
|
47
57
|
const problem = json_problem_at(value[index], path, parents)
|
|
48
|
-
if (problem)
|
|
58
|
+
if (problem) {
|
|
59
|
+
return problem
|
|
60
|
+
}
|
|
49
61
|
path.pop()
|
|
50
62
|
}
|
|
51
63
|
parents.pop()
|
|
52
64
|
return
|
|
53
65
|
}
|
|
54
|
-
|
|
66
|
+
/** @type {{ constructor?: unknown } | null} */
|
|
67
|
+
const prototype = Object.getPrototypeOf(value)
|
|
55
68
|
if (prototype && Object.getPrototypeOf(prototype)) {
|
|
56
69
|
const { constructor } = prototype
|
|
57
70
|
return `an instance of ${typeof constructor == "function" && constructor.name || "a class"}`
|
|
@@ -60,10 +73,14 @@ function json_problem_at(value, path, parents) {
|
|
|
60
73
|
const record = /** @type {Record<string, unknown>} */(value)/**/
|
|
61
74
|
for (const key of Object.keys(record)) {
|
|
62
75
|
const item = record[key]
|
|
63
|
-
if (item === void 0)
|
|
76
|
+
if (item === void 0) {
|
|
77
|
+
continue
|
|
78
|
+
}
|
|
64
79
|
path.push(key)
|
|
65
80
|
const problem = json_problem_at(item, path, parents)
|
|
66
|
-
if (problem)
|
|
81
|
+
if (problem) {
|
|
82
|
+
return problem
|
|
83
|
+
}
|
|
67
84
|
path.pop()
|
|
68
85
|
}
|
|
69
86
|
parents.pop()
|
package/src/durable/lease.js
CHANGED
|
@@ -12,7 +12,9 @@ export const SUSPENDED = Symbol("suspended")
|
|
|
12
12
|
* @returns {void}
|
|
13
13
|
*/
|
|
14
14
|
export function check_halted(d) {
|
|
15
|
-
if (d.halted)
|
|
15
|
+
if (d.halted) {
|
|
16
|
+
throw new CancelError("The worker stopped")
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
18
20
|
* @param {DurableWorker} d
|
|
@@ -37,7 +39,9 @@ export async function claim(d, key, saved, input) {
|
|
|
37
39
|
}
|
|
38
40
|
next.status = "failed"
|
|
39
41
|
} else {
|
|
40
|
-
if (next.status == "pending")
|
|
42
|
+
if (next.status == "pending") {
|
|
43
|
+
next.input = copy(input)
|
|
44
|
+
}
|
|
41
45
|
next.lease = Date.now() + d.lease_ms
|
|
42
46
|
next.owner = d.owner
|
|
43
47
|
next.revision = d.revision
|
|
@@ -59,7 +63,9 @@ export function expiring(d, execution) {
|
|
|
59
63
|
* @returns {boolean}
|
|
60
64
|
*/
|
|
61
65
|
export function is_due(d, saved) {
|
|
62
|
-
if (saved.status == "running")
|
|
66
|
+
if (saved.status == "running") {
|
|
67
|
+
return is_free(d, saved)
|
|
68
|
+
}
|
|
63
69
|
return (saved.status == "sleeping" || saved.status == "waiting") && saved.wake != null && saved.wake <= Date.now()
|
|
64
70
|
}
|
|
65
71
|
/**
|
|
@@ -76,7 +82,9 @@ function is_free(d, saved) {
|
|
|
76
82
|
* @returns {void}
|
|
77
83
|
*/
|
|
78
84
|
export function lose(execution, reason) {
|
|
79
|
-
if (execution.lost)
|
|
85
|
+
if (execution.lost) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
80
88
|
execution.lost = true
|
|
81
89
|
execution.controller.abort(reason)
|
|
82
90
|
execution.interrupt(LOST)
|
|
@@ -86,7 +94,9 @@ export function lose(execution, reason) {
|
|
|
86
94
|
* @returns {Promise<never> | undefined}
|
|
87
95
|
*/
|
|
88
96
|
export function refuse(execution) {
|
|
89
|
-
if (!execution.lost && !execution.finished)
|
|
97
|
+
if (!execution.lost && !execution.finished) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
90
100
|
const { signal } = execution.controller
|
|
91
101
|
return Promise.reject(
|
|
92
102
|
signal.aborted ? signal.reason : new CancelError("The run left this worker")
|
package/src/durable/persist.js
CHANGED
|
@@ -29,7 +29,9 @@ function deliver(execution, item) {
|
|
|
29
29
|
0,
|
|
30
30
|
{ at: item.at, value: item.value }
|
|
31
31
|
)
|
|
32
|
-
if (execution.finished)
|
|
32
|
+
if (execution.finished) {
|
|
33
|
+
wake_if_sent(saved)
|
|
34
|
+
}
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* @param {DurableExecution} execution
|
|
@@ -37,12 +39,16 @@ function deliver(execution, item) {
|
|
|
37
39
|
*/
|
|
38
40
|
function drain(execution) {
|
|
39
41
|
const { saved } = execution
|
|
40
|
-
if (!saved.events || execution.finished)
|
|
42
|
+
if (!saved.events || execution.finished) {
|
|
43
|
+
return
|
|
44
|
+
}
|
|
41
45
|
for (const name of Object.keys(saved.events)) {
|
|
42
46
|
for (;;) {
|
|
43
47
|
const event = saved.events?.[name]?.[0]
|
|
44
48
|
const waiter = event && !execution.unsaved.has(event) && take_waiter(execution, name, event.at)
|
|
45
|
-
if (!event || !waiter)
|
|
49
|
+
if (!event || !waiter) {
|
|
50
|
+
break
|
|
51
|
+
}
|
|
46
52
|
take_event(saved, name)
|
|
47
53
|
give(execution, waiter, event.value)
|
|
48
54
|
waiter.resolve(copy(event.value))
|
|
@@ -55,10 +61,14 @@ function drain(execution) {
|
|
|
55
61
|
* @returns {Promise<boolean>}
|
|
56
62
|
*/
|
|
57
63
|
export async function inbox_read(d, execution) {
|
|
58
|
-
if (execution.writing)
|
|
64
|
+
if (execution.writing) {
|
|
65
|
+
await execution.writing
|
|
66
|
+
}
|
|
59
67
|
try {
|
|
60
68
|
const latest = await load(d.store, execution.key)
|
|
61
|
-
if (execution.lost || execution.finished)
|
|
69
|
+
if (execution.lost || execution.finished) {
|
|
70
|
+
return false
|
|
71
|
+
}
|
|
62
72
|
return execution.fault === void 0 && (!latest?.inbox?.length || latest.version == execution.saved.version) || await persist(d, execution)
|
|
63
73
|
} catch (error) {
|
|
64
74
|
execution.fault = error
|
|
@@ -71,7 +81,9 @@ export async function inbox_read(d, execution) {
|
|
|
71
81
|
* @returns {Promise<boolean>}
|
|
72
82
|
*/
|
|
73
83
|
export function persist(d, execution) {
|
|
74
|
-
if (execution.lost)
|
|
84
|
+
if (execution.lost) {
|
|
85
|
+
return Promise.resolve(false)
|
|
86
|
+
}
|
|
75
87
|
if (execution.writing) {
|
|
76
88
|
execution.dirty = true
|
|
77
89
|
return execution.writing
|
|
@@ -83,9 +95,13 @@ export function persist(d, execution) {
|
|
|
83
95
|
const current = execution.saved
|
|
84
96
|
const next = snapshot(current)
|
|
85
97
|
const included = execution.unsaved
|
|
86
|
-
if (included.size)
|
|
98
|
+
if (included.size) {
|
|
99
|
+
execution.unsaved = new Set()
|
|
100
|
+
}
|
|
87
101
|
const attempt = ++execution.taken
|
|
88
|
-
if (next.owner)
|
|
102
|
+
if (next.owner) {
|
|
103
|
+
next.lease = Date.now() + d.lease_ms
|
|
104
|
+
}
|
|
89
105
|
/** @type {SavedRun | undefined} */
|
|
90
106
|
let latest
|
|
91
107
|
let putting = true
|
|
@@ -105,16 +121,26 @@ export function persist(d, execution) {
|
|
|
105
121
|
continue
|
|
106
122
|
}
|
|
107
123
|
putting = false
|
|
108
|
-
for (const event of included)
|
|
124
|
+
for (const event of included) {
|
|
125
|
+
execution.unsaved.add(event)
|
|
126
|
+
}
|
|
109
127
|
latest = await load(d.store, execution.key)
|
|
110
128
|
} catch (error) {
|
|
111
|
-
for (const event of included)
|
|
112
|
-
|
|
129
|
+
for (const event of included) {
|
|
130
|
+
execution.unsaved.add(event)
|
|
131
|
+
}
|
|
132
|
+
if (putting) {
|
|
133
|
+
execution.tried.push(next)
|
|
134
|
+
}
|
|
113
135
|
execution.fault = error
|
|
114
|
-
if (expiring(d, execution))
|
|
136
|
+
if (expiring(d, execution)) {
|
|
137
|
+
lose(execution, store_error(error))
|
|
138
|
+
}
|
|
139
|
+
return false
|
|
140
|
+
}
|
|
141
|
+
if (execution.lost) {
|
|
115
142
|
return false
|
|
116
143
|
}
|
|
117
|
-
if (execution.lost) return false
|
|
118
144
|
const committed = latest && execution.tried.findLast(
|
|
119
145
|
tried => same_state(
|
|
120
146
|
/** @type {SavedRun} */(latest)/**/,
|
|
@@ -137,10 +163,12 @@ export function persist(d, execution) {
|
|
|
137
163
|
execution.tried = []
|
|
138
164
|
current.version = latest.version
|
|
139
165
|
const inbox = latest.inbox ?? []
|
|
140
|
-
for (let index = execution.absorbed; index < inbox.length; index++)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
166
|
+
for (let index = execution.absorbed; index < inbox.length; index++) {
|
|
167
|
+
deliver(
|
|
168
|
+
execution,
|
|
169
|
+
/** @type {NonNullable<SavedRun["inbox"]>[number]} */(inbox[index])/**/
|
|
170
|
+
)
|
|
171
|
+
}
|
|
144
172
|
execution.absorbed = inbox.length
|
|
145
173
|
execution.dirty = true
|
|
146
174
|
} while (execution.dirty && !execution.lost)
|
|
@@ -158,7 +186,9 @@ export function persist(d, execution) {
|
|
|
158
186
|
*/
|
|
159
187
|
export async function save(d, execution) {
|
|
160
188
|
while (!await persist(d, execution)) {
|
|
161
|
-
if (execution.lost)
|
|
189
|
+
if (execution.lost) {
|
|
190
|
+
return false
|
|
191
|
+
}
|
|
162
192
|
await sleep(
|
|
163
193
|
d.renew_ms,
|
|
164
194
|
execution.controller.signal
|
|
@@ -174,13 +204,21 @@ export async function save(d, execution) {
|
|
|
174
204
|
export function watch_inbox(d, execution) {
|
|
175
205
|
execution.inbox_timer ??= setInterval(
|
|
176
206
|
() => {
|
|
177
|
-
if (execution.finished || execution.lost || execution.writing)
|
|
207
|
+
if (execution.finished || execution.lost || execution.writing) {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
178
210
|
let waiting = false
|
|
179
|
-
for (const list of execution.waiters.values())
|
|
180
|
-
|
|
211
|
+
for (const list of execution.waiters.values()) {
|
|
212
|
+
waiting ||= list.length > 0
|
|
213
|
+
}
|
|
214
|
+
if (!waiting) {
|
|
215
|
+
return
|
|
216
|
+
}
|
|
181
217
|
void load(d.store, execution.key).then(
|
|
182
218
|
latest => {
|
|
183
|
-
if (latest?.inbox?.length && latest.version != execution.saved.version)
|
|
219
|
+
if (latest?.inbox?.length && latest.version != execution.saved.version) {
|
|
220
|
+
void persist(d, execution)
|
|
221
|
+
}
|
|
184
222
|
},
|
|
185
223
|
noop
|
|
186
224
|
)
|