@lostgradient/weft 0.18.0 → 0.19.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 +3 -1
- package/dist/cli/conformance.js +14 -18
- package/dist/cli/generated/operation-catalog.snapshot.json +258 -16
- package/dist/cli/generated/operation-client.generated.d.ts +30 -6
- package/dist/cli/generated/operation-client.generated.js +4 -0
- package/dist/core/context/child-workflow-pipe.d.ts +1 -1
- package/dist/core/context/child-workflow-pipe.js +1 -1
- package/dist/core/engine/construction.d.ts +2 -0
- package/dist/core/engine/construction.js +3 -0
- package/dist/core/engine/index.js +1 -0
- package/dist/core/engine/listing.d.ts +1 -0
- package/dist/core/engine/listing.js +6 -4
- package/dist/core/weft-error.d.ts +1 -1
- package/dist/core/weft-error.js +2 -1
- package/dist/core/worker-execution-dispatcher.d.ts +8 -0
- package/dist/core/worker-execution-dispatcher.js +4 -0
- package/dist/core/worker-execution-strategy-options.d.ts +16 -0
- package/dist/core/worker-execution-strategy.js +71 -89
- package/dist/core/worker-fault-handling.d.ts +45 -0
- package/dist/core/worker-fault-handling.js +88 -0
- package/dist/core/worker-protocol.d.ts +18 -1
- package/dist/core/worker-protocol.js +1 -1
- package/dist/core/worker-realm-readiness.d.ts +78 -0
- package/dist/core/worker-realm-readiness.js +127 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +28 -1
- package/dist/json-schema.js +1 -1
- package/dist/runtime/portable.d.ts +14 -0
- package/dist/runtime/portable.js +10 -0
- package/dist/server/index.d.ts +71 -8
- package/dist/server/index.js +7 -3
- package/dist/server/operations/get-task-diagnostics.d.ts +43 -18
- package/dist/server/operations/get-task-diagnostics.js +87 -126
- package/dist/server/operations/get-worker-diagnostics.d.ts +177 -0
- package/dist/server/operations/get-worker-diagnostics.js +117 -0
- package/dist/server/operations/list-worker-registration-rejections.d.ts +79 -0
- package/dist/server/operations/list-worker-registration-rejections.js +60 -0
- package/dist/server/operations/list-workers.js +1 -3
- package/dist/server/operations/static-registrations.js +5 -20
- package/dist/server/rest-bindings.js +31 -2
- package/dist/server/runtime/authentication-bridge.js +6 -14
- package/dist/server/runtime/context.d.ts +23 -0
- package/dist/server/runtime/task-dispatch.d.ts +7 -1
- package/dist/server/runtime/task-dispatch.js +126 -55
- package/dist/server/runtime/task-ledger-completion.d.ts +68 -0
- package/dist/server/runtime/task-ledger-completion.js +72 -0
- package/dist/server/runtime/task-ledger-recovery.d.ts +55 -0
- package/dist/server/runtime/task-ledger-recovery.js +73 -0
- package/dist/server/runtime/task-ledger-runtime.d.ts +64 -0
- package/dist/server/runtime/task-ledger-runtime.js +34 -0
- package/dist/server/runtime/task-metrics.d.ts +6 -4
- package/dist/server/runtime/task-polling.d.ts +14 -12
- package/dist/server/runtime/task-polling.js +106 -82
- package/dist/server/runtime/task-reconciliation.d.ts +35 -8
- package/dist/server/runtime/task-reconciliation.js +75 -74
- package/dist/server/runtime/task-result-resolution.d.ts +2 -10
- package/dist/server/runtime/task-result-resolution.js +0 -67
- package/dist/server/runtime/task-result-view.d.ts +82 -0
- package/dist/server/runtime/task-result-view.js +48 -0
- package/dist/server/runtime/websocket-worker-messaging.d.ts +16 -0
- package/dist/server/runtime/websocket-worker-messaging.js +32 -0
- package/dist/server/runtime/websocket-worker-registration.d.ts +41 -0
- package/dist/server/runtime/websocket-worker-registration.js +134 -0
- package/dist/server/runtime/websocket-worker.d.ts +0 -1
- package/dist/server/runtime/websocket-worker.js +64 -116
- package/dist/server/serve-internals.d.ts +9 -6
- package/dist/server/serve-internals.js +14 -40
- package/dist/server/task-ledger-codec.d.ts +40 -0
- package/dist/server/task-ledger-codec.js +195 -0
- package/dist/server/task-ledger-keys.d.ts +13 -0
- package/dist/server/task-ledger-keys.js +5 -0
- package/dist/server/task-ledger-limits.d.ts +34 -0
- package/dist/server/task-ledger-limits.js +5 -0
- package/dist/server/task-ledger-transition-helpers.d.ts +38 -0
- package/dist/server/task-ledger-transition-helpers.js +42 -0
- package/dist/server/task-ledger-transitions-cancellation.d.ts +31 -0
- package/dist/server/task-ledger-transitions-cancellation.js +73 -0
- package/dist/server/task-ledger-transitions.d.ts +129 -0
- package/dist/server/task-ledger-transitions.js +162 -0
- package/dist/server/task-ledger-types.d.ts +220 -0
- package/dist/server/task-ledger-types.js +1 -0
- package/dist/server/task-ledger.d.ts +17 -0
- package/dist/server/task-ledger.js +24 -0
- package/dist/server/task-state.d.ts +25 -152
- package/dist/server/task-state.js +0 -188
- package/dist/server/worker-admission-policy.d.ts +70 -0
- package/dist/server/worker-admission-policy.js +0 -0
- package/dist/storage/compressed-storage.js +1 -1
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/interface.d.ts +0 -2
- package/dist/storage/interface.js +1 -1
- package/dist/storage/lmdb.js +1 -1
- package/dist/storage/memory.js +1 -1
- package/dist/storage/neon.js +1 -1
- package/dist/storage/postgres.js +1 -1
- package/dist/storage/resolve.js +1 -1
- package/dist/storage/scoped-storage.js +1 -1
- package/dist/storage/testing.js +1 -1
- package/dist/storage/turso.js +1 -1
- package/dist/storage/web-extension.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/web-extension.js +1 -1
- package/dist/worker/index.d.ts +2 -0
- package/dist/worker/index.js +30 -4
- package/dist/worker/manifest/canonical-json.d.ts +20 -0
- package/dist/worker/manifest/canonical-json.js +13 -0
- package/dist/worker/manifest/capabilities.d.ts +24 -0
- package/dist/worker/manifest/capabilities.js +74 -0
- package/dist/worker/manifest/content-digest.d.ts +20 -0
- package/dist/worker/manifest/content-digest.js +13 -0
- package/dist/worker/manifest/declared-shape-digest.d.ts +14 -0
- package/dist/worker/manifest/declared-shape-digest.js +4 -0
- package/dist/worker/manifest/digest.d.ts +82 -0
- package/dist/worker/manifest/digest.js +9 -0
- package/dist/worker/manifest/execution-identity.d.ts +92 -0
- package/dist/worker/manifest/execution-identity.js +36 -0
- package/dist/worker/manifest/failure.d.ts +59 -0
- package/dist/worker/manifest/failure.js +4 -0
- package/dist/worker/manifest/index.d.ts +22 -0
- package/dist/worker/manifest/index.js +23 -0
- package/dist/worker/manifest/internal-realm.d.ts +50 -0
- package/dist/worker/manifest/internal-realm.js +39 -0
- package/dist/worker/manifest/is-record.d.ts +12 -0
- package/dist/worker/manifest/is-record.js +6 -0
- package/dist/worker/manifest/json-scan.d.ts +26 -0
- package/dist/worker/manifest/json-scan.js +88 -0
- package/dist/worker/manifest/limits.d.ts +138 -0
- package/dist/worker/manifest/limits.js +1 -0
- package/dist/worker/manifest/normalize.d.ts +63 -0
- package/dist/worker/manifest/normalize.js +73 -0
- package/dist/worker/manifest/parse-json.d.ts +24 -0
- package/dist/worker/manifest/parse-json.js +15 -0
- package/dist/worker/manifest/parse.d.ts +86 -0
- package/dist/worker/manifest/parse.js +188 -0
- package/dist/worker/manifest/registry-contract-builder.d.ts +120 -0
- package/dist/worker/manifest/registry-contract-builder.js +65 -0
- package/dist/worker/manifest/types.d.ts +263 -0
- package/dist/worker/manifest/types.js +1 -0
- package/dist/worker/manifest/utf8.d.ts +13 -0
- package/dist/worker/manifest/utf8.js +7 -0
- package/dist/worker/options.d.ts +55 -8
- package/dist/worker/options.js +65 -9
- package/dist/worker/protocol-internals.d.ts +1 -2
- package/dist/worker/protocol-internals.js +0 -5
- package/dist/worker/protocol-messages.d.ts +33 -17
- package/dist/worker/protocol-schemas.d.ts +36 -74
- package/dist/worker/protocol-schemas.js +25 -18
- package/dist/worker/protocol-version.d.ts +18 -14
- package/dist/worker/protocol-version.js +1 -1
- package/dist/worker/protocol.js +1 -1
- package/dist/worker/registry/deployment-consistency.d.ts +78 -0
- package/dist/worker/registry/deployment-consistency.js +27 -0
- package/dist/worker/registry/drain.d.ts +14 -0
- package/dist/worker/registry/drain.js +24 -0
- package/dist/worker/registry/rejections.d.ts +31 -0
- package/dist/worker/registry/rejections.js +10 -0
- package/dist/worker/registry/summary.d.ts +0 -3
- package/dist/worker/registry/summary.js +2 -5
- package/dist/worker/registry/types.d.ts +10 -3
- package/dist/worker/registry.d.ts +47 -2
- package/dist/worker/registry.js +45 -32
- package/dist/workers/workflow-worker-entry.d.ts +12 -7
- package/dist/workers/workflow-worker-entry.js +9 -2
- package/package.json +3 -3
- package/dist/server/task-resolved-record.d.ts +0 -12
- package/dist/server/task-resolved-record.js +0 -35
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { calculateBackoff } from "../core/scheduler.js";
|
|
2
|
+
import {
|
|
3
|
+
pickAttemptFields,
|
|
4
|
+
pickBase,
|
|
5
|
+
pickLeaseHolderFields
|
|
6
|
+
} from "./task-ledger-transition-helpers.js";
|
|
7
|
+
export {
|
|
8
|
+
canDeleteRetainedTerminalTask,
|
|
9
|
+
commitCancellation,
|
|
10
|
+
markWorkflowResultAdopted,
|
|
11
|
+
recordCancellationIntent
|
|
12
|
+
} from "./task-ledger-transitions-cancellation.js";
|
|
13
|
+
export function createQueued(current, input, now) {
|
|
14
|
+
if (current !== null)
|
|
15
|
+
return {
|
|
16
|
+
ok: !1,
|
|
17
|
+
reason: `operation "${input.operationId}" already has a task record in state "${current.state}"`
|
|
18
|
+
};
|
|
19
|
+
return { ok: !0, nextRecord: {
|
|
20
|
+
...pickBase({ ...input, generation: 0 }),
|
|
21
|
+
state: "queued",
|
|
22
|
+
attempt: 1,
|
|
23
|
+
availableAt: input.availableAt ?? now,
|
|
24
|
+
firstQueuedAt: now,
|
|
25
|
+
lastQueuedAt: now,
|
|
26
|
+
retryCount: 0,
|
|
27
|
+
requeueCount: 0
|
|
28
|
+
} };
|
|
29
|
+
}
|
|
30
|
+
export function claimQueued(current, input, now) {
|
|
31
|
+
if (current === null || current.state !== "queued")
|
|
32
|
+
return { ok: !1, reason: 'expected task state "queued"' };
|
|
33
|
+
if (current.generation !== input.expectedGeneration)
|
|
34
|
+
return { ok: !1, reason: "generation mismatch" };
|
|
35
|
+
if (current.availableAt > now)
|
|
36
|
+
return { ok: !1, reason: "task is not yet available" };
|
|
37
|
+
return { ok: !0, nextRecord: {
|
|
38
|
+
...pickBase(current),
|
|
39
|
+
...pickAttemptFields(current),
|
|
40
|
+
generation: current.generation + 1,
|
|
41
|
+
state: "leased",
|
|
42
|
+
attemptToken: input.attemptToken,
|
|
43
|
+
workerSessionId: input.workerSessionId,
|
|
44
|
+
...input.executionIdentity !== void 0 ? { executionIdentity: input.executionIdentity } : {},
|
|
45
|
+
attempt: current.attempt,
|
|
46
|
+
leaseDeadline: now + input.leaseDurationMilliseconds,
|
|
47
|
+
firstQueuedAt: current.firstQueuedAt,
|
|
48
|
+
lastQueuedAt: current.lastQueuedAt,
|
|
49
|
+
startedAt: current.startedAt ?? now,
|
|
50
|
+
lastHeartbeatAt: now
|
|
51
|
+
} };
|
|
52
|
+
}
|
|
53
|
+
export function renewAttemptLease(current, input, now) {
|
|
54
|
+
if (current === null || current.state !== "leased")
|
|
55
|
+
return { ok: !1, reason: 'expected task state "leased"' };
|
|
56
|
+
if (current.attemptToken !== input.attemptToken || current.workerSessionId !== input.workerSessionId)
|
|
57
|
+
return { ok: !1, reason: "attempt token or worker session mismatch" };
|
|
58
|
+
return { ok: !0, nextRecord: {
|
|
59
|
+
...current,
|
|
60
|
+
generation: current.generation + 1,
|
|
61
|
+
leaseDeadline: now + input.leaseDurationMilliseconds,
|
|
62
|
+
lastHeartbeatAt: now
|
|
63
|
+
} };
|
|
64
|
+
}
|
|
65
|
+
export function beginCompletion(current, input) {
|
|
66
|
+
if (current === null || current.state !== "leased")
|
|
67
|
+
return { ok: !1, reason: 'expected task state "leased"' };
|
|
68
|
+
if (current.attemptToken !== input.attemptToken)
|
|
69
|
+
return { ok: !1, reason: "attempt token mismatch" };
|
|
70
|
+
return { ok: !0, nextRecord: {
|
|
71
|
+
...pickBase(current),
|
|
72
|
+
...pickAttemptFields(current),
|
|
73
|
+
...pickLeaseHolderFields(current),
|
|
74
|
+
generation: current.generation + 1,
|
|
75
|
+
state: "completing",
|
|
76
|
+
pendingStatus: input.pendingStatus,
|
|
77
|
+
pendingResultDigest: input.pendingResultDigest
|
|
78
|
+
} };
|
|
79
|
+
}
|
|
80
|
+
export function commitTerminalResult(current, input, now) {
|
|
81
|
+
if (current === null || current.state !== "completing")
|
|
82
|
+
return { ok: !1, reason: 'expected task state "completing"' };
|
|
83
|
+
if (current.attemptToken !== input.attemptToken || current.pendingResultDigest !== input.resultDigest)
|
|
84
|
+
return { ok: !1, reason: "attempt token or result digest mismatch" };
|
|
85
|
+
return { ok: !0, nextRecord: {
|
|
86
|
+
...pickBase(current),
|
|
87
|
+
generation: current.generation + 1,
|
|
88
|
+
state: "terminal",
|
|
89
|
+
disposition: "resolved",
|
|
90
|
+
attempt: current.attempt,
|
|
91
|
+
attemptToken: current.attemptToken,
|
|
92
|
+
status: current.pendingStatus,
|
|
93
|
+
...input.error !== void 0 ? { error: input.error } : {},
|
|
94
|
+
resultDigest: current.pendingResultDigest,
|
|
95
|
+
terminalAt: now,
|
|
96
|
+
adopted: !1,
|
|
97
|
+
retentionGeneration: 0
|
|
98
|
+
} };
|
|
99
|
+
}
|
|
100
|
+
export function requeueExpiredAttempt(current, input, now) {
|
|
101
|
+
if (current === null || current.state !== "leased")
|
|
102
|
+
return { ok: !1, reason: 'expected task state "leased"' };
|
|
103
|
+
if (current.attemptToken !== input.attemptToken)
|
|
104
|
+
return { ok: !1, reason: "attempt token mismatch" };
|
|
105
|
+
if (input.skipDeadlineCheck !== !0 && current.leaseDeadline > now)
|
|
106
|
+
return { ok: !1, reason: "lease has not expired" };
|
|
107
|
+
const nextAttempt = current.attempt + 1, policy = current.retryPolicy;
|
|
108
|
+
if (policy !== void 0 && nextAttempt > policy.maxAttempts)
|
|
109
|
+
return { ok: !0, nextRecord: {
|
|
110
|
+
...pickBase(current),
|
|
111
|
+
generation: current.generation + 1,
|
|
112
|
+
state: "terminal",
|
|
113
|
+
disposition: "retryExhausted",
|
|
114
|
+
attempt: current.attempt,
|
|
115
|
+
attemptToken: current.attemptToken,
|
|
116
|
+
error: `Activity "${current.activityName}" exhausted all ${String(policy.maxAttempts)} retry attempts`,
|
|
117
|
+
resultDigest: `retry-exhausted:${current.operationId}:${current.attemptToken}`,
|
|
118
|
+
terminalAt: now,
|
|
119
|
+
adopted: !1,
|
|
120
|
+
retentionGeneration: 0
|
|
121
|
+
} };
|
|
122
|
+
const availableAt = policy === void 0 ? now : now + calculateBackoff(nextAttempt - 1, policy);
|
|
123
|
+
return { ok: !0, nextRecord: {
|
|
124
|
+
...pickBase(current),
|
|
125
|
+
generation: current.generation + 1,
|
|
126
|
+
state: "queued",
|
|
127
|
+
attempt: nextAttempt,
|
|
128
|
+
availableAt,
|
|
129
|
+
firstQueuedAt: current.firstQueuedAt,
|
|
130
|
+
lastQueuedAt: now,
|
|
131
|
+
lastDispatchedAt: current.lastQueuedAt,
|
|
132
|
+
startedAt: current.startedAt,
|
|
133
|
+
retryCount: Math.max(current.retryCount, nextAttempt - 1),
|
|
134
|
+
requeueCount: current.requeueCount + 1,
|
|
135
|
+
lastRequeueReason: input.requeueReason
|
|
136
|
+
} };
|
|
137
|
+
}
|
|
138
|
+
export function commitDeadLetter(current, input, now) {
|
|
139
|
+
if (current === null || current.state !== "completing")
|
|
140
|
+
return { ok: !1, reason: 'expected task state "completing"' };
|
|
141
|
+
if (current.attemptToken !== input.attemptToken || current.pendingResultDigest !== input.resultDigest)
|
|
142
|
+
return { ok: !1, reason: "attempt token or result digest mismatch" };
|
|
143
|
+
return { ok: !0, nextRecord: {
|
|
144
|
+
...pickBase(current),
|
|
145
|
+
...pickAttemptFields(current),
|
|
146
|
+
generation: current.generation + 1,
|
|
147
|
+
state: "deadLettered",
|
|
148
|
+
attemptToken: current.attemptToken,
|
|
149
|
+
attempt: current.attempt,
|
|
150
|
+
pendingStatus: current.pendingStatus,
|
|
151
|
+
pendingResultDigest: current.pendingResultDigest,
|
|
152
|
+
...input.value !== void 0 ? { value: input.value } : {},
|
|
153
|
+
...input.error !== void 0 ? { error: input.error } : {},
|
|
154
|
+
deadLetteredAt: now,
|
|
155
|
+
persistenceFailureReason: input.persistenceFailureReason
|
|
156
|
+
} };
|
|
157
|
+
}
|
|
158
|
+
export function canClearDeadLetteredTask(current) {
|
|
159
|
+
if (current === null || current.state !== "deadLettered")
|
|
160
|
+
return { ok: !1, reason: 'expected task state "deadLettered"' };
|
|
161
|
+
return { ok: !0 };
|
|
162
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical durable remote task ledger type union (WFT-25).
|
|
3
|
+
*
|
|
4
|
+
* Replaces the fragmented `op:queued:` / `op:inflight:` / `op:resolved:` /
|
|
5
|
+
* `op:dead-letter:` records in `task-state.ts` with one authoritative current
|
|
6
|
+
* state per operation. Every transition between these states proves the
|
|
7
|
+
* expected prior state and attempt identity through `storage.conditionalBatch`
|
|
8
|
+
* — see `task-ledger-transitions.ts` for the pure precondition functions that
|
|
9
|
+
* decide whether a transition is legal.
|
|
10
|
+
*
|
|
11
|
+
* This module defines the record shapes only. It does not read or write
|
|
12
|
+
* storage, and it is not wired into the live dispatch path — `TaskQueue`,
|
|
13
|
+
* `WorkerRegistry`, and the WebSocket/long-poll task handlers keep using
|
|
14
|
+
* `task-state.ts` until "Queue and Claim Coordinator" (WFT-22), the project
|
|
15
|
+
* slice that owns replacing that memory authority, lands.
|
|
16
|
+
*
|
|
17
|
+
* @module server/task-ledger-types
|
|
18
|
+
*/
|
|
19
|
+
import type { JSONValue } from '../core/json.ts';
|
|
20
|
+
import type { RetryPolicy } from '../core/types.ts';
|
|
21
|
+
import type { WorkerExecutionIdentity } from '../worker/manifest/types.ts';
|
|
22
|
+
/**
|
|
23
|
+
* Fields common to every state a task record can occupy — the "complete
|
|
24
|
+
* dispatch envelope" the project brief requires to survive queueing, lease,
|
|
25
|
+
* retry, recovery, resolution, and dead letter.
|
|
26
|
+
*
|
|
27
|
+
* `workflowId` is optional, diverging from the project brief's literal
|
|
28
|
+
* `workflowId: string`. `TaskDispatch.workflowId` (`server/index.ts`) and
|
|
29
|
+
* every existing task record (`QueuedRecord`, `InflightRecord` in
|
|
30
|
+
* `task-state.ts`) already treat it as optional, and `serve-internals.ts`'s
|
|
31
|
+
* `rebuildWorkflowIndex` has a real, non-test code path that tolerates a
|
|
32
|
+
* restored in-flight record with no `workflowId`. Making it required here
|
|
33
|
+
* would silently break that existing, exercised behavior.
|
|
34
|
+
*
|
|
35
|
+
* `workflowExecutionToken` is optional for the same reason: the public
|
|
36
|
+
* `TaskDispatch.workflowExecutionToken` (`server/index.ts`) is already
|
|
37
|
+
* `string | undefined` for standalone remote-activity dispatch outside any
|
|
38
|
+
* durable workflow run, and every other declaration of this field in the
|
|
39
|
+
* codebase (`task-state.ts`, `task-queue-types.ts`, the core execution
|
|
40
|
+
* strategies) is optional too. Absence means "not workflow-bound" and must
|
|
41
|
+
* never be defaulted to an empty string — this field is documented
|
|
42
|
+
* elsewhere as an external write fence, so a shared `''` sentinel would let
|
|
43
|
+
* unrelated standalone tasks appear to hold the same fence.
|
|
44
|
+
*/
|
|
45
|
+
export type RemoteTaskBase = Readonly<{
|
|
46
|
+
recordVersion: 1;
|
|
47
|
+
operationId: string;
|
|
48
|
+
workflowId?: string;
|
|
49
|
+
workflowType: string;
|
|
50
|
+
workflowExecutionToken?: string;
|
|
51
|
+
activityName: string;
|
|
52
|
+
queue: string;
|
|
53
|
+
input: JSONValue;
|
|
54
|
+
headers: Readonly<Record<string, string>>;
|
|
55
|
+
priority?: number;
|
|
56
|
+
fairShareKey?: string;
|
|
57
|
+
/** Preferred worker-affinity routing hint, derived from `sticky ? workflowId : undefined` at dispatch time. */
|
|
58
|
+
stickyWorkflowId?: string;
|
|
59
|
+
visibilityTimeoutMilliseconds: number;
|
|
60
|
+
retryPolicy?: RetryPolicy;
|
|
61
|
+
scheduleToCloseDeadline?: number;
|
|
62
|
+
executionRequirement?: WorkerExecutionRequirementInput;
|
|
63
|
+
createdAt: number;
|
|
64
|
+
/** Monotonic counter incremented on every transition. Diagnostic/provenance surface — `conditionalBatch`'s whole-record byte equality is what actually enforces the CAS, but the precondition functions still check `generation` explicitly because it is the documented contract. */
|
|
65
|
+
generation: number;
|
|
66
|
+
}>;
|
|
67
|
+
/**
|
|
68
|
+
* Local alias for the manifest project's `WorkerExecutionRequirement` — kept
|
|
69
|
+
* as a named alias (rather than importing it directly into every downstream
|
|
70
|
+
* signature) so this module has one place documenting that the ledger reuses
|
|
71
|
+
* WFT-26's routing-input vocabulary rather than defining its own.
|
|
72
|
+
*/
|
|
73
|
+
export type WorkerExecutionRequirementInput = Readonly<{
|
|
74
|
+
deploymentName?: string;
|
|
75
|
+
buildId?: string;
|
|
76
|
+
artifactDigest?: string;
|
|
77
|
+
workflowRevision?: string;
|
|
78
|
+
activityContractHash?: string;
|
|
79
|
+
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Retry/requeue provenance carried by every non-terminal state so it survives
|
|
82
|
+
* a lease → requeue → re-lease cycle intact — matching the existing
|
|
83
|
+
* `TaskLifecycleFields.retryCount` / `requeueCount` semantics in
|
|
84
|
+
* `task-state.ts` (`reassignOrExpireTask`'s `nextRetryCount` /
|
|
85
|
+
* `requeueCount + 1` computation), which this ledger's requeue transition
|
|
86
|
+
* reproduces.
|
|
87
|
+
*/
|
|
88
|
+
export type RemoteTaskAttemptFields = Readonly<{
|
|
89
|
+
retryCount: number;
|
|
90
|
+
requeueCount: number;
|
|
91
|
+
lastRequeueReason?: string;
|
|
92
|
+
}>;
|
|
93
|
+
export type RemoteTaskQueued = RemoteTaskBase & RemoteTaskAttemptFields & Readonly<{
|
|
94
|
+
state: 'queued';
|
|
95
|
+
attempt: number;
|
|
96
|
+
/** Delayed retries are represented here, not by a process timer — `Queued` includes work delayed until `availableAt`. */
|
|
97
|
+
availableAt: number;
|
|
98
|
+
firstQueuedAt: number;
|
|
99
|
+
lastQueuedAt: number;
|
|
100
|
+
lastDispatchedAt?: number;
|
|
101
|
+
/** First time any attempt of this operation began executing. Absent until the first claim; preserved across requeues. */
|
|
102
|
+
startedAt?: number;
|
|
103
|
+
}>;
|
|
104
|
+
export type RemoteTaskLeased = RemoteTaskBase & RemoteTaskAttemptFields & Readonly<{
|
|
105
|
+
state: 'leased';
|
|
106
|
+
attemptToken: string;
|
|
107
|
+
/**
|
|
108
|
+
* Identifies the live worker connection/session holding the lease,
|
|
109
|
+
* distinct from `executionIdentity.workerId` (the durable identity of
|
|
110
|
+
* the worker *process*). No durable session concept exists in the
|
|
111
|
+
* codebase today — `WorkerRegistry`'s grace-period reconnect logic
|
|
112
|
+
* deliberately preserves in-flight ownership across sockets under one
|
|
113
|
+
* `workerId`. This field exists so a later slice (WFT-22) can decide
|
|
114
|
+
* whether lease renewal survives reconnect; that policy is out of this
|
|
115
|
+
* slice's scope.
|
|
116
|
+
*/
|
|
117
|
+
workerSessionId: string;
|
|
118
|
+
/**
|
|
119
|
+
* Complete observed identity of the worker holding the lease — see
|
|
120
|
+
* `WorkerExecutionIdentity` in `worker/manifest/types.ts`. Optional
|
|
121
|
+
* because `buildWorkerExecutionIdentity` returns `undefined` whenever the
|
|
122
|
+
* claiming worker has no registered manifest entry for this
|
|
123
|
+
* workflowType/activityName pair — which is the *only* case for every
|
|
124
|
+
* long-poll claim (long-poll workers never call `WorkerRegistry.register`,
|
|
125
|
+
* so they never have a manifest) and can also occur for a WebSocket
|
|
126
|
+
* worker whose manifest doesn't cover the dispatched activity. Absence
|
|
127
|
+
* here means "no verifiable provenance was available at claim time," not
|
|
128
|
+
* "provenance was skipped" — nothing fabricates a placeholder identity.
|
|
129
|
+
*/
|
|
130
|
+
executionIdentity?: WorkerExecutionIdentity;
|
|
131
|
+
attempt: number;
|
|
132
|
+
leaseDeadline: number;
|
|
133
|
+
firstQueuedAt: number;
|
|
134
|
+
lastQueuedAt: number;
|
|
135
|
+
startedAt: number;
|
|
136
|
+
lastHeartbeatAt: number;
|
|
137
|
+
}>;
|
|
138
|
+
export type RemoteTaskCompleting = RemoteTaskBase & RemoteTaskAttemptFields & Readonly<{
|
|
139
|
+
state: 'completing';
|
|
140
|
+
attemptToken: string;
|
|
141
|
+
workerSessionId: string;
|
|
142
|
+
executionIdentity?: WorkerExecutionIdentity;
|
|
143
|
+
attempt: number;
|
|
144
|
+
leaseDeadline: number;
|
|
145
|
+
firstQueuedAt: number;
|
|
146
|
+
lastQueuedAt: number;
|
|
147
|
+
startedAt: number;
|
|
148
|
+
lastHeartbeatAt: number;
|
|
149
|
+
pendingStatus: 'completed' | 'failed';
|
|
150
|
+
/** Digest of the pending result, matched by "Commit terminal result" before it is applied. */
|
|
151
|
+
pendingResultDigest: string;
|
|
152
|
+
}>;
|
|
153
|
+
export type RemoteTaskCancelling = RemoteTaskBase & RemoteTaskAttemptFields & Readonly<{
|
|
154
|
+
state: 'cancelling';
|
|
155
|
+
/**
|
|
156
|
+
* Always present. Per the state diagram, `Cancelling` is reached only
|
|
157
|
+
* from `Leased` (`Leased --> Cancelling: cancellation intent`) — a
|
|
158
|
+
* cancellation recorded while a task is still `Queued` transitions
|
|
159
|
+
* directly to `Terminal` (disposition `cancelled`, no attempt ever
|
|
160
|
+
* existed) without passing through this state. The brief's transition
|
|
161
|
+
* table phrase "attempt token matches when one exists" describes that
|
|
162
|
+
* generic precondition-checking function across both origins; this
|
|
163
|
+
* type only represents the leased-origin case.
|
|
164
|
+
*/
|
|
165
|
+
attemptToken: string;
|
|
166
|
+
workerSessionId: string;
|
|
167
|
+
executionIdentity?: WorkerExecutionIdentity;
|
|
168
|
+
attempt: number;
|
|
169
|
+
leaseDeadline: number;
|
|
170
|
+
firstQueuedAt: number;
|
|
171
|
+
lastQueuedAt: number;
|
|
172
|
+
startedAt: number;
|
|
173
|
+
lastHeartbeatAt: number;
|
|
174
|
+
cancellationReason: string;
|
|
175
|
+
cancellationRequestedAt: number;
|
|
176
|
+
}>;
|
|
177
|
+
/** Which lineage produced a terminal record. Every lineage carries `resultDigest` so "Mark workflow result adopted" can match uniformly regardless of disposition. */
|
|
178
|
+
export type RemoteTaskTerminalDisposition = 'resolved' | 'cancelled' | 'retryExhausted';
|
|
179
|
+
type RemoteTaskTerminalCommon = RemoteTaskBase & Readonly<{
|
|
180
|
+
state: 'terminal';
|
|
181
|
+
attempt: number;
|
|
182
|
+
resultDigest: string;
|
|
183
|
+
terminalAt: number;
|
|
184
|
+
adopted: boolean;
|
|
185
|
+
adoptedAt?: number;
|
|
186
|
+
/** Matched by "Delete retained terminal task"; incremented if a record is re-terminalized (e.g. adoption retried after a partial cleanup). */
|
|
187
|
+
retentionGeneration: number;
|
|
188
|
+
}>;
|
|
189
|
+
export type RemoteTaskTerminalResolved = RemoteTaskTerminalCommon & Readonly<{
|
|
190
|
+
disposition: 'resolved';
|
|
191
|
+
attemptToken: string;
|
|
192
|
+
status: 'completed' | 'failed';
|
|
193
|
+
error?: string;
|
|
194
|
+
}>;
|
|
195
|
+
export type RemoteTaskTerminalCancelled = RemoteTaskTerminalCommon & Readonly<{
|
|
196
|
+
disposition: 'cancelled';
|
|
197
|
+
/** Present when cancelled mid-attempt (via `Cancelling`); absent when cancelled directly from `Queued`. */
|
|
198
|
+
attemptToken?: string;
|
|
199
|
+
cancellationReason: string;
|
|
200
|
+
}>;
|
|
201
|
+
export type RemoteTaskTerminalRetryExhausted = RemoteTaskTerminalCommon & Readonly<{
|
|
202
|
+
disposition: 'retryExhausted';
|
|
203
|
+
attemptToken: string;
|
|
204
|
+
error: string;
|
|
205
|
+
}>;
|
|
206
|
+
export type RemoteTaskTerminal = RemoteTaskTerminalResolved | RemoteTaskTerminalCancelled | RemoteTaskTerminalRetryExhausted;
|
|
207
|
+
export type RemoteTaskDeadLettered = RemoteTaskBase & RemoteTaskAttemptFields & Readonly<{
|
|
208
|
+
state: 'deadLettered';
|
|
209
|
+
attemptToken: string;
|
|
210
|
+
attempt: number;
|
|
211
|
+
pendingStatus: 'completed' | 'failed';
|
|
212
|
+
pendingResultDigest: string;
|
|
213
|
+
value?: JSONValue;
|
|
214
|
+
error?: string;
|
|
215
|
+
deadLetteredAt: number;
|
|
216
|
+
persistenceFailureReason: string;
|
|
217
|
+
}>;
|
|
218
|
+
export type RemoteTaskRecord = RemoteTaskQueued | RemoteTaskLeased | RemoteTaskCompleting | RemoteTaskCancelling | RemoteTaskTerminal | RemoteTaskDeadLettered;
|
|
219
|
+
export declare const REMOTE_TASK_RECORD_VERSION = 1;
|
|
220
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const REMOTE_TASK_RECORD_VERSION = 1;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable remote task ledger — public surface for this subsystem (WFT-25).
|
|
3
|
+
*
|
|
4
|
+
* Barrel re-exporting the record types, storage key, and codec split across
|
|
5
|
+
* `task-ledger-types.ts`, `task-ledger-limits.ts`, `task-ledger-keys.ts`, and
|
|
6
|
+
* `task-ledger-codec.ts` so callers (and `task-ledger.test.ts`, named by the
|
|
7
|
+
* project's verification gate) import from one module. Server-internal only
|
|
8
|
+
* — not re-exported from `src/index.ts`. See `task-ledger-transitions.ts`
|
|
9
|
+
* for the pure conditional-transition precondition functions.
|
|
10
|
+
*
|
|
11
|
+
* @module server/task-ledger
|
|
12
|
+
*/
|
|
13
|
+
export { decodeRemoteTaskRecord, encodeRemoteTaskRecord, isRemoteTaskCancelling, isRemoteTaskCompleting, isRemoteTaskDeadLettered, isRemoteTaskLeased, isRemoteTaskQueued, isRemoteTaskRecord, isRemoteTaskTerminal, isRemoteTaskTerminalCancelled, isRemoteTaskTerminalResolved, isRemoteTaskTerminalRetryExhausted, isValidTaskHeaders, } from './task-ledger-codec.ts';
|
|
14
|
+
export { taskLedgerKey } from './task-ledger-keys.ts';
|
|
15
|
+
export { MAX_TASK_HEADER_COUNT, MAX_TASK_HEADER_VALUE_BYTES, MAX_TASK_IDENTIFIER_BYTES, MAX_TASK_REASON_BYTES, utf8ByteLength, } from './task-ledger-limits.ts';
|
|
16
|
+
export { REMOTE_TASK_RECORD_VERSION } from './task-ledger-types.ts';
|
|
17
|
+
export type { RemoteTaskAttemptFields, RemoteTaskBase, RemoteTaskCancelling, RemoteTaskCompleting, RemoteTaskDeadLettered, RemoteTaskLeased, RemoteTaskQueued, RemoteTaskRecord, RemoteTaskTerminal, RemoteTaskTerminalCancelled, RemoteTaskTerminalDisposition, RemoteTaskTerminalResolved, RemoteTaskTerminalRetryExhausted, WorkerExecutionRequirementInput, } from './task-ledger-types.ts';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export {
|
|
2
|
+
decodeRemoteTaskRecord,
|
|
3
|
+
encodeRemoteTaskRecord,
|
|
4
|
+
isRemoteTaskCancelling,
|
|
5
|
+
isRemoteTaskCompleting,
|
|
6
|
+
isRemoteTaskDeadLettered,
|
|
7
|
+
isRemoteTaskLeased,
|
|
8
|
+
isRemoteTaskQueued,
|
|
9
|
+
isRemoteTaskRecord,
|
|
10
|
+
isRemoteTaskTerminal,
|
|
11
|
+
isRemoteTaskTerminalCancelled,
|
|
12
|
+
isRemoteTaskTerminalResolved,
|
|
13
|
+
isRemoteTaskTerminalRetryExhausted,
|
|
14
|
+
isValidTaskHeaders
|
|
15
|
+
} from "./task-ledger-codec.js";
|
|
16
|
+
export { taskLedgerKey } from "./task-ledger-keys.js";
|
|
17
|
+
export {
|
|
18
|
+
MAX_TASK_HEADER_COUNT,
|
|
19
|
+
MAX_TASK_HEADER_VALUE_BYTES,
|
|
20
|
+
MAX_TASK_IDENTIFIER_BYTES,
|
|
21
|
+
MAX_TASK_REASON_BYTES,
|
|
22
|
+
utf8ByteLength
|
|
23
|
+
} from "./task-ledger-limits.js";
|
|
24
|
+
export { REMOTE_TASK_RECORD_VERSION } from "./task-ledger-types.js";
|
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Lifecycle vocabulary and timing calculators shared by the durable task
|
|
3
|
+
* ledger and its diagnostics/metrics consumers.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* The `op:queued:`/`op:inflight:`/`op:resolved:`/`op:dead-letter:` record
|
|
6
|
+
* shapes and type guards this module once exported alongside these
|
|
7
|
+
* calculators are gone: WFT-22 replaced the key scheme with the durable
|
|
8
|
+
* task ledger (`task-ledger.ts`), and WFT-24 migrated `get-task-diagnostics.ts`
|
|
9
|
+
* (the last production reader of those legacy shapes) onto the ledger.
|
|
10
|
+
* What remains is still load-bearing: `TaskLifecycleFields` and
|
|
11
|
+
* `TaskRequeueReason` back the ledger's own record types, and the
|
|
12
|
+
* queue-latency, execution-latency, and heartbeat-staleness calculators
|
|
13
|
+
* back `task-metrics.ts` and the ledger diagnostics.
|
|
12
14
|
*
|
|
13
15
|
* @module task-state
|
|
14
16
|
*/
|
|
15
|
-
import type { RetryPolicy } from '../core/types.ts';
|
|
16
|
-
import type { Storage } from '../storage/interface.ts';
|
|
17
|
-
/** The three exclusive states a dispatched task can occupy. */
|
|
18
|
-
export type TaskState = 'queued' | 'inflight' | 'resolved';
|
|
19
17
|
/** Why a task was requeued before another dispatch attempt. */
|
|
20
18
|
export type TaskRequeueReason = 'visibility-timeout' | 'worker-disconnect';
|
|
21
|
-
/** Final reason captured when a task reaches the resolved state. */
|
|
22
|
-
export type TaskResolutionReason = 'completed' | 'failed' | 'cancelled' | 'max-attempts-exceeded';
|
|
23
|
-
/** Why a task-result transition was moved to the operator dead-letter guard. */
|
|
24
|
-
export type TaskDeadLetterReason = 'result-resolution-storage-exhausted';
|
|
25
19
|
/** Lifecycle evidence persisted with task records for diagnostics. */
|
|
26
20
|
export interface TaskLifecycleFields {
|
|
27
21
|
/** First time this operation entered a task queue. */
|
|
@@ -43,146 +37,25 @@ export interface TaskLifecycleFields {
|
|
|
43
37
|
/** Most recent reason this task moved back to queued. */
|
|
44
38
|
lastRequeueReason?: TaskRequeueReason | undefined;
|
|
45
39
|
}
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
queuedAt: number;
|
|
56
|
-
/** Workflow that dispatched this activity. Present when the dispatch included a workflowId. */
|
|
57
|
-
workflowId?: string | undefined;
|
|
58
|
-
/** Durable token for the workflow run that dispatched this activity, when known. */
|
|
59
|
-
workflowExecutionToken?: string | undefined;
|
|
60
|
-
}
|
|
61
|
-
/** Persisted record for a task in the inflight state. */
|
|
62
|
-
export interface InflightRecord extends TaskLifecycleFields {
|
|
63
|
-
operationId: string;
|
|
64
|
-
workerId: string;
|
|
65
|
-
deadline: number;
|
|
66
|
-
activityName: string;
|
|
67
|
-
queue: string;
|
|
68
|
-
input: unknown;
|
|
69
|
-
attempt: number;
|
|
70
|
-
visibilityTimeout: number;
|
|
71
|
-
retryPolicy?: RetryPolicy | undefined;
|
|
72
|
-
/** Workflow that dispatched this activity. Present when the dispatch included a workflowId. */
|
|
73
|
-
workflowId?: string | undefined;
|
|
74
|
-
/** Durable token for the workflow run that dispatched this activity, when known. */
|
|
75
|
-
workflowExecutionToken?: string | undefined;
|
|
76
|
-
/** Unique, unguessable token identifying this dispatch attempt. */
|
|
77
|
-
attemptToken: string;
|
|
78
|
-
}
|
|
79
|
-
/** Persisted record for a task in the resolved state. */
|
|
80
|
-
export interface ResolvedRecord {
|
|
81
|
-
operationId: string;
|
|
82
|
-
status: 'completed' | 'failed';
|
|
83
|
-
resolvedAt: number;
|
|
84
|
-
value?: unknown;
|
|
85
|
-
error?: string | undefined;
|
|
86
|
-
activityName?: string | undefined;
|
|
87
|
-
queue?: string | undefined;
|
|
88
|
-
workerId?: string | undefined;
|
|
89
|
-
attempt?: number | undefined;
|
|
90
|
-
visibilityTimeout?: number | undefined;
|
|
91
|
-
/** Workflow that dispatched this activity. Present when the dispatch included a workflowId. */
|
|
92
|
-
workflowId?: string | undefined;
|
|
93
|
-
firstQueuedAt?: number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The subset of {@link TaskLifecycleFields} the queue-latency, execution-latency,
|
|
42
|
+
* and heartbeat-staleness calculations actually read. Deliberately narrower
|
|
43
|
+
* than `TaskLifecycleFields` so these calculations also accept the durable
|
|
44
|
+
* remote task ledger's records (`RemoteTaskLeased`, `RemoteTaskQueued` —
|
|
45
|
+
* WFT-22), which carry the same timing fields but a free-text
|
|
46
|
+
* `lastRequeueReason` rather than the fixed {@link TaskRequeueReason} enum.
|
|
47
|
+
*/
|
|
48
|
+
export type TaskTimingFields = Readonly<{
|
|
94
49
|
lastQueuedAt?: number | undefined;
|
|
95
50
|
lastDispatchedAt?: number | undefined;
|
|
96
51
|
startedAt?: number | undefined;
|
|
97
|
-
completedAt?: number | undefined;
|
|
98
52
|
lastHeartbeatAt?: number | undefined;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
queueLatencyMs?: number | undefined;
|
|
104
|
-
executionLatencyMs?: number | undefined;
|
|
105
|
-
}
|
|
106
|
-
/** Durable operator guard for a task result whose resolved write exhausted retries. */
|
|
107
|
-
export interface DeadLetteredTaskRecord {
|
|
108
|
-
operationId: string;
|
|
109
|
-
reason: TaskDeadLetterReason;
|
|
110
|
-
deadLetteredAt: number;
|
|
111
|
-
errorMessage: string;
|
|
112
|
-
retryAttempts: number;
|
|
113
|
-
status: 'completed' | 'failed';
|
|
114
|
-
activityName?: string | undefined;
|
|
115
|
-
queue?: string | undefined;
|
|
116
|
-
workerId?: string | undefined;
|
|
117
|
-
attempt?: number | undefined;
|
|
118
|
-
visibilityTimeout?: number | undefined;
|
|
119
|
-
workflowId?: string | undefined;
|
|
120
|
-
retryCount?: number | undefined;
|
|
121
|
-
requeueCount?: number | undefined;
|
|
122
|
-
lastRequeueReason?: TaskRequeueReason | undefined;
|
|
123
|
-
}
|
|
124
|
-
export interface TransitionInflightToResolvedOptions {
|
|
125
|
-
resolutionReason?: TaskResolutionReason;
|
|
126
|
-
resolvedAt?: number;
|
|
127
|
-
record?: InflightRecord;
|
|
128
|
-
value?: unknown;
|
|
129
|
-
error?: string | undefined;
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Look up the current durable state of a task.
|
|
133
|
-
*
|
|
134
|
-
* Returns the state name if the task is found in any of the three
|
|
135
|
-
* states, or `null` if no record exists (the task was never dispatched
|
|
136
|
-
* or its resolved record has been garbage-collected).
|
|
137
|
-
*/
|
|
138
|
-
export declare function getTaskState(storage: Storage, operationId: string): Promise<TaskState | null>;
|
|
139
|
-
/**
|
|
140
|
-
* Return the task state and verify it occupies exactly one state.
|
|
141
|
-
*
|
|
142
|
-
* Throws if the task is found in multiple states simultaneously —
|
|
143
|
-
* this indicates a bug in the state machine.
|
|
144
|
-
*/
|
|
145
|
-
export declare function getExclusiveTaskState(storage: Storage, operationId: string): Promise<TaskState | null>;
|
|
146
|
-
/** Type guard for decoded storage records in the queued state. */
|
|
147
|
-
export declare function isQueuedRecord(value: unknown): value is QueuedRecord;
|
|
148
|
-
/** Type guard for decoded storage records in the inflight state. */
|
|
149
|
-
export declare function isInflightRecord(value: unknown): value is InflightRecord;
|
|
150
|
-
/** Type guard for decoded storage records in the resolved state. */
|
|
151
|
-
export declare function isResolvedRecord(value: unknown): value is ResolvedRecord;
|
|
152
|
-
/** Type guard for decoded task-result dead-letter records. */
|
|
153
|
-
export declare function isDeadLetteredTaskRecord(value: unknown): value is DeadLetteredTaskRecord;
|
|
154
|
-
/** Decode the queued record for an operation, returning null when absent or malformed. */
|
|
155
|
-
export declare function readQueuedRecord(storage: Storage, operationId: string): Promise<QueuedRecord | null>;
|
|
156
|
-
/** Decode the inflight record for an operation, returning null when absent or malformed. */
|
|
157
|
-
export declare function readInflightRecord(storage: Storage, operationId: string): Promise<InflightRecord | null>;
|
|
158
|
-
/** Decode the task-result dead-letter record for an operation. */
|
|
159
|
-
export declare function readDeadLetteredTaskRecord(storage: Storage, operationId: string): Promise<DeadLetteredTaskRecord | null>;
|
|
160
|
-
/** True when reconciliation should not re-dispatch the operation. */
|
|
161
|
-
export declare function isTaskDeadLettered(storage: Storage, operationId: string): Promise<boolean>;
|
|
162
|
-
/** Persist a task-result dead-letter guard. */
|
|
163
|
-
export declare function writeDeadLetteredTaskRecord(storage: Storage, record: DeadLetteredTaskRecord): Promise<void>;
|
|
164
|
-
/** Clear a task-result dead-letter guard so reconciliation may handle the inflight record again. */
|
|
165
|
-
export declare function clearDeadLetteredTaskRecord(storage: Storage, operationId: string): Promise<void>;
|
|
166
|
-
export declare function calculateQueueLatencyMs(record: TaskLifecycleFields): number | undefined;
|
|
167
|
-
export declare function calculateExecutionLatencyMs(record: TaskLifecycleFields, completedAt: number): number | undefined;
|
|
168
|
-
export declare function calculateHeartbeatAgeMs(record: TaskLifecycleFields & {
|
|
53
|
+
}>;
|
|
54
|
+
export declare function calculateQueueLatencyMs(record: TaskTimingFields): number | undefined;
|
|
55
|
+
export declare function calculateExecutionLatencyMs(record: TaskTimingFields, completedAt: number): number | undefined;
|
|
56
|
+
export declare function calculateHeartbeatAgeMs(record: TaskTimingFields & {
|
|
169
57
|
deadline?: number | undefined;
|
|
170
58
|
}, currentTime: number): number | undefined;
|
|
171
|
-
export declare function isHeartbeatStale(record:
|
|
59
|
+
export declare function isHeartbeatStale(record: TaskTimingFields & {
|
|
172
60
|
deadline?: number | undefined;
|
|
173
61
|
}, currentTime: number, staleAfterMs: number): boolean;
|
|
174
|
-
/** Write the initial queued record for a newly dispatched task. */
|
|
175
|
-
export declare function markQueued(storage: Storage, record: QueuedRecord): Promise<QueuedRecord>;
|
|
176
|
-
type TransitionQueuedToInflightOptions = {
|
|
177
|
-
readonly queuedRecord?: QueuedRecord | null;
|
|
178
|
-
readonly now?: number | undefined;
|
|
179
|
-
};
|
|
180
|
-
/** Atomically transition a task from queued → inflight. */
|
|
181
|
-
export declare function transitionQueuedToInflight(storage: Storage, operationId: string, inflightRecord: InflightRecord, options?: TransitionQueuedToInflightOptions): Promise<InflightRecord>;
|
|
182
|
-
/** Write the initial inflight record (for tasks dispatched directly to a WS worker). */
|
|
183
|
-
export declare function markInflight(storage: Storage, record: InflightRecord): Promise<void>;
|
|
184
|
-
/** Atomically transition a task from inflight → resolved. */
|
|
185
|
-
export declare function transitionInflightToResolved(storage: Storage, operationId: string, status: 'completed' | 'failed', options?: TransitionInflightToResolvedOptions): Promise<void>;
|
|
186
|
-
/** Atomically transition a task from inflight → queued (requeue on disconnect/timeout). */
|
|
187
|
-
export declare function transitionInflightToQueued(storage: Storage, operationId: string, queuedRecord: QueuedRecord): Promise<void>;
|
|
188
|
-
export {};
|