@ewhauser/world-celld 0.3.1 → 0.3.2
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 +8 -0
- package/README.md +11 -9
- package/celld-worker/README.md +3 -3
- package/celld-worker/worker.ts +0 -1
- package/celld-worker/wrangler.jsonc +0 -2
- package/dist/index.d.ts +22 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -20
- package/dist/index.js.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +492 -205
- package/dist/testing.js.map +1 -1
- package/dist/{util-DmO0XkFw.js → util-ya3V_FTA.js} +32 -19
- package/dist/util-ya3V_FTA.js.map +1 -0
- package/dist/worker.d.ts +49 -23
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +519 -217
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/util-DmO0XkFw.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.3.2 (2026-08-19)
|
|
6
|
+
|
|
7
|
+
## What's Changed
|
|
8
|
+
* fix: compact expired-run lifecycle fences by @ewhauser in https://github.com/ewhauser/world-celld/pull/29
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
**Full Changelog**: https://github.com/ewhauser/world-celld/compare/v0.3.1...v0.3.2
|
|
12
|
+
|
|
5
13
|
## 0.3.1 (2026-08-19)
|
|
6
14
|
|
|
7
15
|
## What's Changed
|
package/README.md
CHANGED
|
@@ -120,7 +120,6 @@ Workflow application
|
|
|
120
120
|
celld worker router
|
|
121
121
|
|-- WorkflowRunDO one cell per workflow run
|
|
122
122
|
|-- RunCatalogDO 16 stable run-id shards; merged ordered listing
|
|
123
|
-
|-- RunFenceDO one lifecycle fence cell per workflow run
|
|
124
123
|
|-- HookTokenDO 32 stable token-ownership shards
|
|
125
124
|
|-- HookIdDO 32 stable hook-id lookup shards
|
|
126
125
|
|-- StreamDO stream chunks and run/stream indexes
|
|
@@ -141,17 +140,20 @@ Index routing is a versioned hard-cutover protocol. Run catalog writes hash the
|
|
|
141
140
|
`runId` across 16 shards, while hook ownership and hook-ID lookup hash their
|
|
142
141
|
natural keys across 32 shards each. A single stateless worker request queries
|
|
143
142
|
all 16 catalog shards in parallel and merges their lexicographic pages before
|
|
144
|
-
authoritative RunDO reads.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
fence resolve ambiguous delivery without pretending
|
|
149
|
-
form a cross-Durable-Object transaction. Stateless cohesive index routes keep
|
|
143
|
+
authoritative RunDO reads. The RunDO is also the only permanent lifecycle
|
|
144
|
+
authority: hook shards consult it directly, while queue and catalog expiry
|
|
145
|
+
fences compact after bounded protocol leases. Token and hook-ID admission are
|
|
146
|
+
each transactional inside their natural-key shards. Exact claim IDs plus a
|
|
147
|
+
serialized cancellation fence resolve ambiguous delivery without pretending
|
|
148
|
+
the two ownership shards form a cross-Durable-Object transaction. Stateless cohesive index routes keep
|
|
150
149
|
catalog listing, terminal commits, hook finalization, and hook release to one
|
|
151
150
|
public request each while exposing the internal shard work in measurements.
|
|
152
151
|
|
|
153
152
|
The routing rationale and before/after RPC, storage, latency, and contention
|
|
154
153
|
evidence are recorded in [`docs/index-sharding.md`](./docs/index-sharding.md).
|
|
154
|
+
The expiry authority, producer/consumer map, bounded horizons, and
|
|
155
|
+
post-compaction costs are recorded in
|
|
156
|
+
[`docs/lifecycle-compaction.md`](./docs/lifecycle-compaction.md).
|
|
155
157
|
|
|
156
158
|
## Configuration
|
|
157
159
|
|
|
@@ -168,7 +170,7 @@ variable is shown below.
|
|
|
168
170
|
| `runRetentionMs` | `CELLD_RUN_RETENTION_MS` | `0` (disabled) |
|
|
169
171
|
| `streamLongPollMs` | — | `20000` |
|
|
170
172
|
| `streamFlushIntervalMs` | — | `0` |
|
|
171
|
-
| `rpcTimeoutMs` | — | `30000`
|
|
173
|
+
| `rpcTimeoutMs` | — | `30000` (max `300000`) |
|
|
172
174
|
|
|
173
175
|
The deployed worker also accepts these celld variables:
|
|
174
176
|
|
|
@@ -178,7 +180,7 @@ The deployed worker also accepts these celld variables:
|
|
|
178
180
|
| `WORKFLOW_CALLBACK_SECRET` | none | Sent with deliveries as `x-workflow-callback-secret` |
|
|
179
181
|
| `QUEUE_MAX_ATTEMPTS` | `5` | Attempts before a message is dead-lettered |
|
|
180
182
|
| `QUEUE_MAX_INFLIGHT` | `5` | Concurrent deliveries per queue cell (maximum `128`) |
|
|
181
|
-
| `QUEUE_DELIVERY_TIMEOUT_MS` | `300000` |
|
|
183
|
+
| `QUEUE_DELIVERY_TIMEOUT_MS` | `300000` | Callback timeout (maximum `300000`) |
|
|
182
184
|
|
|
183
185
|
`queueShards` is part of queue placement and is pinned when a queue cell is
|
|
184
186
|
first used. Drain pending work before changing it.
|
package/celld-worker/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# world-celld worker
|
|
2
2
|
|
|
3
|
-
The celld-deployable half of `@ewhauser/world-celld`:
|
|
4
|
-
(WorkflowRunDO, RunCatalogDO,
|
|
5
|
-
|
|
3
|
+
The celld-deployable half of `@ewhauser/world-celld`: six cell classes
|
|
4
|
+
(WorkflowRunDO, RunCatalogDO, HookTokenDO, HookIdDO, StreamDO, and QueueDO)
|
|
5
|
+
behind an authenticated HTTP router.
|
|
6
6
|
Storage, control, and queue methods use fixed JSON RPC routes; stream chunks use
|
|
7
7
|
bounded binary batch writes and binary long-poll reads.
|
|
8
8
|
|
package/celld-worker/worker.ts
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
{ "name": "WORKFLOW_DB", "class_name": "WorkflowRunDO" },
|
|
11
11
|
{ "name": "WORKFLOW_STREAMS", "class_name": "StreamDO" },
|
|
12
12
|
{ "name": "WORKFLOW_RUN_CATALOG", "class_name": "RunCatalogDO" },
|
|
13
|
-
{ "name": "WORKFLOW_RUN_FENCES", "class_name": "RunFenceDO" },
|
|
14
13
|
{ "name": "WORKFLOW_HOOK_TOKENS", "class_name": "HookTokenDO" },
|
|
15
14
|
{ "name": "WORKFLOW_HOOK_IDS", "class_name": "HookIdDO" },
|
|
16
15
|
{ "name": "WORKFLOW_QUEUE", "class_name": "QueueDO" },
|
|
@@ -23,7 +22,6 @@
|
|
|
23
22
|
"WorkflowRunDO",
|
|
24
23
|
"StreamDO",
|
|
25
24
|
"RunCatalogDO",
|
|
26
|
-
"RunFenceDO",
|
|
27
25
|
"HookTokenDO",
|
|
28
26
|
"HookIdDO",
|
|
29
27
|
"QueueDO",
|
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,10 @@ interface RunTombstone {
|
|
|
28
28
|
completedAt: Date;
|
|
29
29
|
expiredAt: Date;
|
|
30
30
|
tombstonedAt: Date;
|
|
31
|
+
/** Final cleanup accounting retained inside the single authoritative record. */
|
|
32
|
+
cleanup: CleanupRecord;
|
|
31
33
|
}
|
|
34
|
+
type RunLifecycleStatus = 'active' | 'terminal' | 'expired' | 'missing';
|
|
32
35
|
type RunReadOutcome<T> = {
|
|
33
36
|
ok: true;
|
|
34
37
|
value: T;
|
|
@@ -45,8 +48,6 @@ interface HookIndexReference {
|
|
|
45
48
|
interface ReleaseHookIndexesRequest {
|
|
46
49
|
runId: string;
|
|
47
50
|
hooks: HookIndexReference[];
|
|
48
|
-
/** Install a fence that prevents delayed hook finalization after terminal state. */
|
|
49
|
-
terminal: boolean;
|
|
50
51
|
}
|
|
51
52
|
interface ReleaseHookIndexesResult {
|
|
52
53
|
deleted: number;
|
|
@@ -77,10 +78,22 @@ interface ExpireStreamResult {
|
|
|
77
78
|
bytes: number;
|
|
78
79
|
done: boolean;
|
|
79
80
|
}
|
|
80
|
-
interface
|
|
81
|
+
interface QueueExpiryReceipt {
|
|
82
|
+
expiredAt: number;
|
|
83
|
+
deleted: number;
|
|
84
|
+
}
|
|
85
|
+
type ExpireQueueRunResult = {
|
|
81
86
|
/** Cumulative messages removed for this run in this queue shard. */
|
|
82
87
|
deleted: number;
|
|
83
|
-
|
|
88
|
+
} & ({
|
|
89
|
+
done: false;
|
|
90
|
+
} | {
|
|
91
|
+
done: true;
|
|
92
|
+
/** Durable receipt which the cleanup coordinator must acknowledge. */
|
|
93
|
+
receipt: QueueExpiryReceipt;
|
|
94
|
+
});
|
|
95
|
+
interface AcknowledgeQueueExpiryResult {
|
|
96
|
+
acknowledged: boolean;
|
|
84
97
|
}
|
|
85
98
|
interface ScheduleCleanupRequest {
|
|
86
99
|
retentionMs: number;
|
|
@@ -146,6 +159,8 @@ interface ApplyEventSuccess {
|
|
|
146
159
|
hasMore?: boolean;
|
|
147
160
|
/** Server-owned event ceiling advertised on run lifecycle writes. */
|
|
148
161
|
maxEvents?: number;
|
|
162
|
+
/** Deadline for publishing this authoritative mutation to derivative indexes. */
|
|
163
|
+
indexPublicationExpiresAt?: number;
|
|
149
164
|
}
|
|
150
165
|
type ApplyEventOutcome = ApplyEventSuccess | ApplyEventFailure;
|
|
151
166
|
//#endregion
|
|
@@ -163,6 +178,7 @@ interface WorkflowRunDOStub {
|
|
|
163
178
|
}): Promise<{
|
|
164
179
|
committed: boolean;
|
|
165
180
|
}>;
|
|
181
|
+
getLifecycleStatus(): Promise<RunLifecycleStatus>;
|
|
166
182
|
getRun(): Promise<RunReadOutcome<WorkflowRun | null>>;
|
|
167
183
|
getStep(stepId: string): Promise<RunReadOutcome<Step | null>>;
|
|
168
184
|
getEvent(eventId: string): Promise<RunReadOutcome<Event | null>>;
|
|
@@ -326,6 +342,7 @@ interface QueueCellStub {
|
|
|
326
342
|
expireRun(runId: string, expiredAt: number, options?: {
|
|
327
343
|
limit?: number;
|
|
328
344
|
}): Promise<ExpireQueueRunResult>;
|
|
345
|
+
acknowledgeExpireRun(runId: string, receipt: QueueExpiryReceipt): Promise<AcknowledgeQueueExpiryResult>;
|
|
329
346
|
}
|
|
330
347
|
interface QueueCellNamespace {
|
|
331
348
|
idFromName(name: string): {
|
|
@@ -365,7 +382,7 @@ type HookReservationResult = {
|
|
|
365
382
|
};
|
|
366
383
|
/** High-level client used by the World storage layer and retention coordinator. */
|
|
367
384
|
interface WorkflowIndex {
|
|
368
|
-
commitRun(run: WorkflowRun, serializedMetadata: string): Promise<{
|
|
385
|
+
commitRun(run: WorkflowRun, serializedMetadata: string, publicationExpiresAt: number): Promise<{
|
|
369
386
|
stored: boolean;
|
|
370
387
|
}>;
|
|
371
388
|
listRuns(options?: IndexListOptions): Promise<IndexListPage>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/retention.ts","../src/apply-event.ts","../src/storage.ts","../src/stream-protocol.ts","../src/streamer.ts","../src/queue.ts","../src/indexes.ts","../src/config.ts","../src/index.ts"],"mappings":";;KAOY;UAEK;EACf;EACA;EACA;EACA,WAAW;EACX,aAAa;EACb,gBAAgB;EAChB,OAAO;EACP;EACA,OAAO;;EAEP;EACA;EACA;EACA,gBAAgB;EAChB,eAAe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA,gBAAgB;EAChB,aAAa;EACb,WAAW;EACX,cAAc;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/retention.ts","../src/apply-event.ts","../src/storage.ts","../src/stream-protocol.ts","../src/streamer.ts","../src/queue.ts","../src/indexes.ts","../src/config.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as decodeStreamReadResult, D as encodeStreamWriteBatch, S as STREAM_BATCH_CONTENT_TYPE, T as decodeStreamWriteResult, _ as MAX_STREAM_ERROR_BYTES, a as stringify, b as MAX_STREAM_READ_CHUNKS, g as MAX_STREAM_CHUNK_BYTES, h as MAX_STREAM_BATCH_BYTES, i as parse, k as normalizeStreamError, n as rpcParse, o as createWorkflowIndex, r as rpcStringify, t as compact, u as MAX_FLEET_RPC_TIMEOUT_MS, v as MAX_STREAM_LONG_POLL_MS, x as MAX_STREAM_WRITE_CHUNKS, y as MAX_STREAM_READ_BYTES } from "./util-ya3V_FTA.js";
|
|
2
2
|
import { EventSchema, HookSchema, MessageId, SPEC_VERSION_CURRENT, StepSchema, WorkflowRunSchema, isTerminalWorkflowRunStatus, parseQueueName } from "@workflow/world";
|
|
3
3
|
import { EntityConflictError, HookNotFoundError, RunExpiredError, RunNotSupportedError, TooEarlyError, WorkflowRunNotFoundError, WorkflowWorldError } from "@workflow/errors";
|
|
4
4
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
@@ -9,7 +9,7 @@ function resolveConfig(config) {
|
|
|
9
9
|
const runRetentionMs = typeof retentionRaw === "number" ? retentionRaw : Number.parseInt(retentionRaw, 10);
|
|
10
10
|
if (!Number.isSafeInteger(runRetentionMs) || runRetentionMs < 0) throw new Error("world-celld: runRetentionMs must be a non-negative safe integer");
|
|
11
11
|
const rpcTimeoutMs = config?.rpcTimeoutMs ?? 3e4;
|
|
12
|
-
if (!Number.isSafeInteger(rpcTimeoutMs) || rpcTimeoutMs < 1) throw new Error(
|
|
12
|
+
if (!Number.isSafeInteger(rpcTimeoutMs) || rpcTimeoutMs < 1 || rpcTimeoutMs > 3e5) throw new Error(`world-celld: rpcTimeoutMs must be between 1 and ${MAX_FLEET_RPC_TIMEOUT_MS}`);
|
|
13
13
|
const streamLongPollMs = config?.streamLongPollMs ?? Math.min(2e4, Math.max(1, rpcTimeoutMs - 1e3));
|
|
14
14
|
if (!Number.isSafeInteger(streamLongPollMs) || streamLongPollMs < 1 || streamLongPollMs > 2e4) throw new Error(`world-celld: streamLongPollMs must be between 1 and ${MAX_STREAM_LONG_POLL_MS}`);
|
|
15
15
|
if (streamLongPollMs >= rpcTimeoutMs) throw new Error("world-celld: streamLongPollMs must be less than rpcTimeoutMs");
|
|
@@ -79,6 +79,8 @@ async function callFleetRoute(transport, path, args, opts) {
|
|
|
79
79
|
const doFetch = transport.fetchImpl ?? fetch;
|
|
80
80
|
const url = `${transport.fleetUrl.replace(/\/$/, "")}${path}`;
|
|
81
81
|
const attempts = opts?.idempotent ? 3 : 1;
|
|
82
|
+
const timeoutMs = transport.timeoutMs ?? DEFAULT_TIMEOUT_MS$1;
|
|
83
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 3e5) throw new Error(`world-celld: fleet RPC timeout must be between 1 and ${MAX_FLEET_RPC_TIMEOUT_MS}`);
|
|
82
84
|
let lastError;
|
|
83
85
|
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
84
86
|
if (attempt > 1) await delayMs$1(100 * attempt + Math.random() * 200);
|
|
@@ -91,7 +93,7 @@ async function callFleetRoute(transport, path, args, opts) {
|
|
|
91
93
|
authorization: `Bearer ${transport.secret}`
|
|
92
94
|
},
|
|
93
95
|
body: rpcStringify(args),
|
|
94
|
-
signal: AbortSignal.timeout(
|
|
96
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
95
97
|
});
|
|
96
98
|
} catch (error) {
|
|
97
99
|
lastError = new FleetTransportError(`world-celld: fleet unreachable at ${url}`, error);
|
|
@@ -258,6 +260,7 @@ async function readStreamChunks(transport, name, request, signal) {
|
|
|
258
260
|
const RUNS = {
|
|
259
261
|
methods: [
|
|
260
262
|
"applyEvent",
|
|
263
|
+
"getLifecycleStatus",
|
|
261
264
|
"getRun",
|
|
262
265
|
"getStep",
|
|
263
266
|
"getEvent",
|
|
@@ -318,14 +321,16 @@ const QUEUE = {
|
|
|
318
321
|
"redriveDeadLetter",
|
|
319
322
|
"purgeDeadLetters",
|
|
320
323
|
"rearmAlarm",
|
|
321
|
-
"expireRun"
|
|
324
|
+
"expireRun",
|
|
325
|
+
"acknowledgeExpireRun"
|
|
322
326
|
],
|
|
323
327
|
mutating: /* @__PURE__ */ new Set([
|
|
324
328
|
"enqueue",
|
|
325
329
|
"redriveDeadLetter",
|
|
326
330
|
"purgeDeadLetters",
|
|
327
331
|
"rearmAlarm",
|
|
328
|
-
"expireRun"
|
|
332
|
+
"expireRun",
|
|
333
|
+
"acknowledgeExpireRun"
|
|
329
334
|
])
|
|
330
335
|
};
|
|
331
336
|
function makeStub(transport, binding, name, spec) {
|
|
@@ -351,14 +356,6 @@ const RUN_CATALOG = {
|
|
|
351
356
|
],
|
|
352
357
|
mutating: /* @__PURE__ */ new Set()
|
|
353
358
|
};
|
|
354
|
-
const RUN_FENCES = {
|
|
355
|
-
methods: [
|
|
356
|
-
"getStatus",
|
|
357
|
-
"fenceTerminal",
|
|
358
|
-
"fenceExpired"
|
|
359
|
-
],
|
|
360
|
-
mutating: /* @__PURE__ */ new Set()
|
|
361
|
-
};
|
|
362
359
|
const HOOK_TOKENS = {
|
|
363
360
|
methods: [
|
|
364
361
|
"get",
|
|
@@ -381,12 +378,10 @@ const HOOK_IDS = {
|
|
|
381
378
|
};
|
|
382
379
|
function createRemoteEnv(transport) {
|
|
383
380
|
const runCatalog = makeNamespace(transport, "run-catalog", RUN_CATALOG);
|
|
384
|
-
const runFences = makeNamespace(transport, "run-fences", RUN_FENCES);
|
|
385
381
|
const hookTokens = makeNamespace(transport, "hook-tokens", HOOK_TOKENS);
|
|
386
382
|
const hookIds = makeNamespace(transport, "hook-ids", HOOK_IDS);
|
|
387
383
|
const workflowIndex = createWorkflowIndex({
|
|
388
384
|
runCatalog,
|
|
389
|
-
runFences,
|
|
390
385
|
hookTokens,
|
|
391
386
|
hookIds
|
|
392
387
|
});
|
|
@@ -395,7 +390,11 @@ function createRemoteEnv(transport) {
|
|
|
395
390
|
WORKFLOW_STREAMS: makeStreamNamespace(transport),
|
|
396
391
|
WORKFLOW_INDEX: {
|
|
397
392
|
...workflowIndex,
|
|
398
|
-
commitRun: (run, serializedMetadata) => callFleetRoute(transport, "/v1/index/runs/commit", [
|
|
393
|
+
commitRun: (run, serializedMetadata, publicationExpiresAt) => callFleetRoute(transport, "/v1/index/runs/commit", [
|
|
394
|
+
run,
|
|
395
|
+
serializedMetadata,
|
|
396
|
+
publicationExpiresAt
|
|
397
|
+
], { idempotent: true }),
|
|
399
398
|
listRuns: (options) => callFleetRoute(transport, "/v1/index/runs/list", [options], { idempotent: true }),
|
|
400
399
|
expireRun: (request) => callFleetRoute(transport, "/v1/index/runs/expire", [request], { idempotent: true }),
|
|
401
400
|
reserveHook: (token, owner) => callFleetRoute(transport, "/v1/index/hooks/reserve", [token, owner], { idempotent: true }),
|
|
@@ -940,17 +939,16 @@ function createStorage(config) {
|
|
|
940
939
|
createdAt: outcome.run.createdAt.toISOString(),
|
|
941
940
|
status: outcome.run.status
|
|
942
941
|
});
|
|
943
|
-
|
|
942
|
+
if (outcome.indexPublicationExpiresAt === void 0) throw new Error("world-celld: authoritative run mutation omitted its index lease");
|
|
943
|
+
await env.WORKFLOW_INDEX.commitRun(outcome.run, meta, outcome.indexPublicationExpiresAt);
|
|
944
944
|
}
|
|
945
945
|
if (outcome.hookToIndex) {
|
|
946
946
|
const serialized = stringify(outcome.hookToIndex);
|
|
947
947
|
await env.WORKFLOW_INDEX.finalizeHookIndexes(outcome.hookToIndex.token, outcome.hookToIndex.hookId, serialized, hookOwner(outcome.hookToIndex), hookAdmission?.reservation);
|
|
948
948
|
} else if (hookAdmission) await env.WORKFLOW_INDEX.releaseHookReservation(hookAdmission.token, hookAdmission.owner, hookAdmission.reservation);
|
|
949
|
-
const terminal = Boolean(outcome.run && isTerminalWorkflowRunStatus(outcome.run.status));
|
|
950
949
|
if (outcome.releasedHooks.length > 0) await env.WORKFLOW_INDEX.releaseHookIndexes({
|
|
951
950
|
runId: effectiveRunId,
|
|
952
|
-
hooks: outcome.releasedHooks
|
|
953
|
-
terminal
|
|
951
|
+
hooks: outcome.releasedHooks
|
|
954
952
|
});
|
|
955
953
|
const eventPage = outcome.events === void 0 ? {} : {
|
|
956
954
|
events: outcome.events,
|