@ewhauser/world-celld 0.8.0 → 0.8.1
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 +9 -0
- package/README.md +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -37
- package/dist/index.js.map +1 -1
- package/dist/queue-consumer.d.ts +1 -1
- package/dist/queue-consumer.js +1 -1
- package/dist/{queue-delivery-BdeNUbRN.d.ts → queue-delivery-wvPp6_Hh.d.ts} +2 -1
- package/dist/{queue-delivery-BdeNUbRN.d.ts.map → queue-delivery-wvPp6_Hh.d.ts.map} +1 -1
- package/dist/{queue-protocol-DKYt8qZJ.js → queue-protocol-C1zbXwa_.js} +5 -2
- package/dist/queue-protocol-C1zbXwa_.js.map +1 -0
- package/dist/{run-list-C987PkJ2.js → run-list-DGsdv6Jf.js} +5 -2
- package/dist/{run-list-C987PkJ2.js.map → run-list-DGsdv6Jf.js.map} +1 -1
- package/dist/testing.js +405 -180
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +33 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +408 -183
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/queue-protocol-DKYt8qZJ.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.8.1 (2026-10-02)
|
|
6
|
+
|
|
7
|
+
## What's Changed
|
|
8
|
+
* fix: harden workflow fault recovery by @ewhauser in https://github.com/ewhauser/world-celld/pull/87
|
|
9
|
+
* chore(deps): bump hono from 4.13.2 to 4.13.7 by @dependabot[bot] in https://github.com/ewhauser/world-celld/pull/88
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
**Full Changelog**: https://github.com/ewhauser/world-celld/compare/v0.8.0...v0.8.1
|
|
13
|
+
|
|
5
14
|
## 0.8.0 (2026-09-27)
|
|
6
15
|
|
|
7
16
|
## What's Changed
|
package/README.md
CHANGED
|
@@ -316,6 +316,11 @@ fleet-wide maximum age are both enabled, the earlier deadline wins.
|
|
|
316
316
|
|
|
317
317
|
- Delivery is at least once. Workflow steps and other external side effects
|
|
318
318
|
must be idempotent.
|
|
319
|
+
- A concurrent enqueue with the same idempotency key returns a retryable `503`
|
|
320
|
+
while broker publication is pending. Publication confirmation starts the
|
|
321
|
+
normal deduplication window. If a producer stops before publication completes,
|
|
322
|
+
its pending reservation can be replaced after five minutes. Broker delivery
|
|
323
|
+
also confirms publication when the producer's confirmation was interrupted.
|
|
319
324
|
- Native Queue operations are administered with celld's `queue info`, `peek`,
|
|
320
325
|
`pause`, `resume`, `purge`, and `redrive` commands.
|
|
321
326
|
- Run cells expose retention status, scheduling, immediate cleanup, and alarm
|
package/dist/index.d.ts
CHANGED
|
@@ -175,6 +175,11 @@ interface WorkflowRunDOStub {
|
|
|
175
175
|
}): Promise<{
|
|
176
176
|
committed: boolean;
|
|
177
177
|
}>;
|
|
178
|
+
resolveExpiredHookClaim(request: {
|
|
179
|
+
hookId: string;
|
|
180
|
+
claimId: string;
|
|
181
|
+
token?: string;
|
|
182
|
+
}): Promise<Hook | null>;
|
|
178
183
|
getLifecycleStatus(): Promise<RunLifecycleStatus>;
|
|
179
184
|
getRun(): Promise<RunReadOutcome<WorkflowRun | null>>;
|
|
180
185
|
getStep(stepId: string): Promise<RunReadOutcome<Step | null>>;
|
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-protocol.ts","../src/queue.ts","../src/run-list.ts","../src/indexes.ts","../src/config.ts","../src/index.ts"],"mappings":";;KAOY;UAEK;EACf;EACA;EACA;EACA,WAAW;;EAEX,SAAS;;EAET,cAAc;;EAEd,iBAAiB;EACjB;EACA,OAAO;EACP,OAAO;;EAEP;EACA;EACA;EACA,gBAAgB;EAChB,eAAe;EACf;EACA;;EAEA;;UAGe;EACf;EACA;;EAEA,SAAS;EACT,cAAc;EACd,iBAAiB;EACjB,WAAW;EACX,cAAc;;EAEd,SAAS;;KAGC;KAEA,eAAe;EACrB;EAAU,OAAO;;EACjB;EAAW;EAAqB;EAAiB,WAAW;;UAEjD;EACf;EACA;;UAae;EACf;EACA,OAAO;;UAGQ;EACf;;UAGe;EACf;EACA,OAAO;EACP;;UAGe;EACf;;UAGe;EACf;;UAGe;;EAEf;EACA;;UAGe;;EAEf;;EAEA;;EAEA;EACA;;UAGe;EACf;;;;UC0Ce;;EAEf;EACA,MAAM,qBAAqB;;EAE3B,SAAS;;;;;EAKT;IAAgB;IAAe;;;EAE/B;;EAEA,UAAU;;KAiFA;UAWK;EACf;EACA,MAAM;EACN;;EAEA;;EAEA;;UAGe;EACf;;EAEA,QAAQ;EACR,MAAM;EACN,OAAO;EACP,OAAO;EACP,OAAO;;EAEP;;EAEA,eAAe;IAAQ;IAAgB;;;EAEvC;IAAe;IAAsB,WAAW;;;EAEhD,cAAc;;EAEd,SAAS;;EAET;EACA;;EAEA;;EAEA;;EAEA;;EAEA;;;;;EAKA,YAAY;;KAGF,oBAAoB,oBAAoB;;;;;;;UClPnC;EACf,WAAW,SAAS,oBAAoB,QAAQ;EAChD,sBAAsB;IACpB;IACA;IACA;MACE;IAAU;;EACd,sBAAsB,QADlB;EAEJ,UAAU,QAAQ,eAAe;EACjC,QAAQ,iBAAiB,QAAQ,eAAe;EAChD,SAAS,kBAAkB,QAAQ,eAAe;EAClD,WAAW;IACT;IACA;IACA;MACE,QAAQ;IAAiB,MAAM;IAAS;IAAuB;;EACnE,UAAU;IACR;IACA;IACA;MACE,QAAQ;IAAiB,MAAM;IAAQ;IAAuB;;EAClE,UAAU;IACR;IACA;IACA;MACE,QAAQ;IAAiB,MAAM;IAAQ;IAAuB;;EAClE,oBAAoB,QADhB;EAEJ,gBACE,SAFkB,yBAGjB,QADiC;EAEpC,WACE,SAFC,yBAGA,QADiC;EAEpC,gBAAgB,QADb;;UAIY;EACf,WAAW,eAAe;EAC1B,IAAI,IAAI,sBAAsB;;UAGf;EACf;;;;;;;;
|
|
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-protocol.ts","../src/queue.ts","../src/run-list.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 { A as checkedQueueTimestampAdd, B as MAX_STREAM_READ_BYTES, D as MAX_QUEUE_DERIVED_DEADLINE_HEADROOM_MS, E as MAX_QUEUE_DELIVERY_TIMEOUT_MS, F as strictIntegerSetting, G as decodeStreamReadResult, H as MAX_STREAM_WRITE_CHUNKS, I as MAX_STREAM_BATCH_BYTES, L as MAX_STREAM_CHUNK_BYTES, P as queueDelayDeadline, Q as normalizeStreamError, R as MAX_STREAM_ERROR_BYTES, T as MAX_FLEET_RPC_TIMEOUT_MS, U as STREAM_BATCH_CONTENT_TYPE, V as MAX_STREAM_READ_CHUNKS, W as STREAM_CHUNK_LIMIT_HEADER, Y as encodeStreamWriteBatch, Z as isChunkLimitRejection, _ as rpcStringify, b as createWorkflowIndex, c as nativeQueueDelaySeconds, g as rpcParse, h as compact, k as boundedIntegerOption, l as queueClaimName, n as listRunsPage, q as decodeStreamWriteResult, v as parse, x as runIndexMetadata, y as stringify, z as MAX_STREAM_LONG_POLL_MS } from "./run-list-DGsdv6Jf.js";
|
|
2
2
|
import { CreateEventSchema, EventSchema, HookSchema, MessageId, QueuePayloadSchema, SPEC_VERSION_CURRENT, StepSchema, WaitSchema, WorkflowRunSchema, parseQueueName } from "@workflow/world";
|
|
3
3
|
import { EntityConflictError, HookNotFoundError, RunExpiredError, RunNotSupportedError, TooEarlyError, WorkflowRunNotFoundError, WorkflowWorldError } from "@workflow/errors";
|
|
4
4
|
import { monotonicFactory } from "ulid";
|
|
@@ -106,7 +106,13 @@ async function callFleetRoute(transport, path, args, opts) {
|
|
|
106
106
|
if (attempt < attempts) continue;
|
|
107
107
|
throw lastError;
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
let text;
|
|
110
|
+
try {
|
|
111
|
+
text = await response.text();
|
|
112
|
+
} catch (error) {
|
|
113
|
+
lastError = new FleetTransportError(`world-celld: interrupted error response from ${url}`, error);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
110
116
|
let wire;
|
|
111
117
|
try {
|
|
112
118
|
wire = JSON.parse(text).error;
|
|
@@ -240,7 +246,9 @@ async function writeStreamChunks(transport, name, runId, chunks) {
|
|
|
240
246
|
if (!response.ok) throw await errorFromResponse(response);
|
|
241
247
|
recordStreamChunkLimit(transport, response);
|
|
242
248
|
try {
|
|
243
|
-
|
|
249
|
+
const result = decodeStreamWriteResult(await readBoundedResponse(response, MAX_WRITE_RESPONSE_BYTES));
|
|
250
|
+
if (result.count !== chunks.length) throw new Error("Stream write acknowledgement does not match the requested chunk count");
|
|
251
|
+
return result;
|
|
244
252
|
} catch (error) {
|
|
245
253
|
if (error instanceof FleetTransportError) throw error;
|
|
246
254
|
throw new FleetTransportError(`world-celld: malformed stream response from ${url.href}`, error);
|
|
@@ -256,6 +264,7 @@ async function readStreamChunks(transport, name, request, signal) {
|
|
|
256
264
|
url.searchParams.set("waitMs", String(request.waitMs));
|
|
257
265
|
const doFetch = transport.fetchImpl ?? fetch;
|
|
258
266
|
let lastError;
|
|
267
|
+
let maxChunks = request.maxChunks;
|
|
259
268
|
for (let attempt = 1; attempt <= READ_ATTEMPTS; attempt++) {
|
|
260
269
|
if (signal?.aborted) throw aborted(signal);
|
|
261
270
|
if (attempt > 1) await delayMs(100 * attempt + Math.random() * 200, signal);
|
|
@@ -278,7 +287,9 @@ async function readStreamChunks(transport, name, request, signal) {
|
|
|
278
287
|
if (response.ok) {
|
|
279
288
|
recordStreamChunkLimit(transport, response);
|
|
280
289
|
try {
|
|
281
|
-
|
|
290
|
+
const result = decodeStreamReadResult(await readBoundedResponse(response, MAX_READ_RESPONSE_BYTES));
|
|
291
|
+
if (result.startIndex !== request.startIndex || result.chunks.length > maxChunks || result.chunks.reduce((bytes, chunk) => bytes + chunk.byteLength, 0) > request.maxBytes || result.chunks.length > 0 && result.startIndex + result.chunks.length - 1 > result.tailIndex || maxChunks > 0 && result.chunks.length === 0 && result.startIndex <= result.tailIndex && result.state !== "expired") throw new Error("Stream read response does not match the requested range and bounds");
|
|
292
|
+
return result;
|
|
282
293
|
} catch (error) {
|
|
283
294
|
if (signal?.aborted) throw aborted(signal);
|
|
284
295
|
lastError = error instanceof FleetTransportError ? error : new FleetTransportError(`world-celld: malformed stream response from ${url.href}`, error);
|
|
@@ -299,6 +310,7 @@ async function readStreamChunks(transport, name, request, signal) {
|
|
|
299
310
|
}
|
|
300
311
|
if (request.maxChunks > 32 && isChunkLimitRejection(error) && attempt < READ_ATTEMPTS) {
|
|
301
312
|
resetStreamChunkLimit(transport);
|
|
313
|
+
maxChunks = 32;
|
|
302
314
|
url.searchParams.set("maxChunks", String(32));
|
|
303
315
|
lastError = error;
|
|
304
316
|
continue;
|
|
@@ -323,14 +335,16 @@ const RUNS = {
|
|
|
323
335
|
"scheduleCleanup",
|
|
324
336
|
"cleanupNow",
|
|
325
337
|
"rearmCleanup",
|
|
326
|
-
"resolveHookTokenClaim"
|
|
338
|
+
"resolveHookTokenClaim",
|
|
339
|
+
"resolveExpiredHookClaim"
|
|
327
340
|
],
|
|
328
341
|
mutating: /* @__PURE__ */ new Set([
|
|
329
342
|
"applyEvent",
|
|
330
343
|
"scheduleCleanup",
|
|
331
344
|
"cleanupNow",
|
|
332
345
|
"rearmCleanup",
|
|
333
|
-
"resolveHookTokenClaim"
|
|
346
|
+
"resolveHookTokenClaim",
|
|
347
|
+
"resolveExpiredHookClaim"
|
|
334
348
|
])
|
|
335
349
|
};
|
|
336
350
|
const STREAMS = {
|
|
@@ -581,7 +595,7 @@ function createTestPump(config) {
|
|
|
581
595
|
const inflightMessages = /* @__PURE__ */ new Map();
|
|
582
596
|
let running = false;
|
|
583
597
|
function release(envelope) {
|
|
584
|
-
if (envelope.idempotencyKey) inflightMessages.delete(envelope.idempotencyKey);
|
|
598
|
+
if (envelope.idempotencyKey) inflightMessages.delete(queueClaimName(envelope.queueName, envelope.idempotencyKey));
|
|
585
599
|
}
|
|
586
600
|
function enqueue(pathname, envelope) {
|
|
587
601
|
queues[pathname].push(envelope);
|
|
@@ -594,6 +608,24 @@ function createTestPump(config) {
|
|
|
594
608
|
wakers[pathname].push(() => resolve(queues[pathname].shift() ?? null));
|
|
595
609
|
});
|
|
596
610
|
}
|
|
611
|
+
function retry(envelope, pathname, reason) {
|
|
612
|
+
if (envelope.attempt >= maxAttempts) {
|
|
613
|
+
release(envelope);
|
|
614
|
+
console.error(`[world-celld test pump] dropping ${envelope.messageId} after ${envelope.attempt} attempts: ${reason}`);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
const next = {
|
|
618
|
+
...envelope,
|
|
619
|
+
attempt: envelope.attempt + 1
|
|
620
|
+
};
|
|
621
|
+
const backoff = Math.min(MAX_TEST_PUMP_BACKOFF_MS, baseBackoffMs * 2 ** Math.min(next.attempt - 1, 30));
|
|
622
|
+
if (checkedQueueTimestampAdd(Date.now(), backoff, 900001) === null) {
|
|
623
|
+
release(envelope);
|
|
624
|
+
console.error(`[world-celld test pump] dropping ${envelope.messageId}: retry deadline exceeds the queue timestamp horizon`);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
delayFor(backoff).then(() => enqueue(pathname, next));
|
|
628
|
+
}
|
|
597
629
|
async function dispatch(envelope, pathname) {
|
|
598
630
|
const url = `${resolveBaseUrl(config)}/.well-known/workflow/v1/${pathname}`;
|
|
599
631
|
const response = await fetch(url, {
|
|
@@ -607,11 +639,12 @@ function createTestPump(config) {
|
|
|
607
639
|
body: stringify(envelope.message),
|
|
608
640
|
signal: AbortSignal.timeout(httpTimeoutMs)
|
|
609
641
|
});
|
|
610
|
-
if (response.ok) {
|
|
642
|
+
if (response.ok || PERMANENT_ERROR_STATUSES.has(response.status)) {
|
|
611
643
|
try {
|
|
612
644
|
await response.body?.cancel();
|
|
613
645
|
} catch {}
|
|
614
646
|
release(envelope);
|
|
647
|
+
if (!response.ok) debug(`[world-celld test pump] dropping ${envelope.messageId}: permanent HTTP ${response.status}`);
|
|
615
648
|
return;
|
|
616
649
|
}
|
|
617
650
|
const text = await response.text();
|
|
@@ -630,27 +663,7 @@ function createTestPump(config) {
|
|
|
630
663
|
return;
|
|
631
664
|
}
|
|
632
665
|
}
|
|
633
|
-
|
|
634
|
-
release(envelope);
|
|
635
|
-
debug(`[world-celld test pump] dropping ${envelope.messageId}: permanent HTTP ${response.status}: ${text}`);
|
|
636
|
-
return;
|
|
637
|
-
}
|
|
638
|
-
if (envelope.attempt < maxAttempts) {
|
|
639
|
-
const next = {
|
|
640
|
-
...envelope,
|
|
641
|
-
attempt: envelope.attempt + 1
|
|
642
|
-
};
|
|
643
|
-
const backoff = Math.min(MAX_TEST_PUMP_BACKOFF_MS, baseBackoffMs * 2 ** Math.min(next.attempt - 1, 30));
|
|
644
|
-
if (checkedQueueTimestampAdd(Date.now(), backoff, 900001) === null) {
|
|
645
|
-
release(envelope);
|
|
646
|
-
console.error(`[world-celld test pump] dropping ${envelope.messageId}: retry deadline exceeds the queue timestamp horizon`);
|
|
647
|
-
return;
|
|
648
|
-
}
|
|
649
|
-
delayFor(backoff).then(() => enqueue(pathname, next));
|
|
650
|
-
} else {
|
|
651
|
-
release(envelope);
|
|
652
|
-
console.error(`[world-celld test pump] dropping ${envelope.messageId} after ${envelope.attempt} attempts: HTTP ${response.status}: ${text}`);
|
|
653
|
-
}
|
|
666
|
+
retry(envelope, pathname, `HTTP ${response.status}: ${text}`);
|
|
654
667
|
}
|
|
655
668
|
async function loop(pathname) {
|
|
656
669
|
while (true) {
|
|
@@ -660,19 +673,18 @@ function createTestPump(config) {
|
|
|
660
673
|
try {
|
|
661
674
|
await dispatch(envelope, pathname);
|
|
662
675
|
} catch (err) {
|
|
663
|
-
|
|
664
|
-
console.error(`[world-celld test pump] dispatch error on ${pathname}:`, err);
|
|
676
|
+
retry(envelope, pathname, err instanceof Error ? err.message : String(err));
|
|
665
677
|
}
|
|
666
678
|
}
|
|
667
679
|
}
|
|
668
680
|
return {
|
|
669
681
|
/** Returns the inflight messageId when the key is already claimed. */
|
|
670
|
-
inflight(idempotencyKey) {
|
|
671
|
-
return idempotencyKey ? inflightMessages.get(idempotencyKey) : void 0;
|
|
682
|
+
inflight(queueName, idempotencyKey) {
|
|
683
|
+
return idempotencyKey ? inflightMessages.get(queueClaimName(queueName, idempotencyKey)) : void 0;
|
|
672
684
|
},
|
|
673
685
|
push(pathname, envelope, delaySeconds) {
|
|
674
686
|
if (queueDelayDeadline(Date.now(), delaySeconds ?? 0, 0, 900001) === null) throw new Error("world-celld queue delaySeconds lacks required delivery headroom");
|
|
675
|
-
if (envelope.idempotencyKey) inflightMessages.set(envelope.idempotencyKey, MessageId.parse(envelope.messageId));
|
|
687
|
+
if (envelope.idempotencyKey) inflightMessages.set(queueClaimName(envelope.queueName, envelope.idempotencyKey), MessageId.parse(envelope.messageId));
|
|
676
688
|
if (delaySeconds && delaySeconds > 0) delayFor(delaySeconds * 1e3).then(() => enqueue(pathname, envelope));
|
|
677
689
|
else enqueue(pathname, envelope);
|
|
678
690
|
},
|
|
@@ -700,7 +712,7 @@ function createQueue(config) {
|
|
|
700
712
|
if (queueDelayDeadline(Date.now(), opts?.delaySeconds ?? 0, 0, 900001) === null) throw new Error("world-celld queue delaySeconds lacks required delivery headroom");
|
|
701
713
|
const runId = "runId" in parsedMessage.data && typeof parsedMessage.data.runId === "string" ? parsedMessage.data.runId : void 0;
|
|
702
714
|
if (isTestMode()) {
|
|
703
|
-
const existing = testPump.inflight(opts?.idempotencyKey);
|
|
715
|
+
const existing = testPump.inflight(queueName, opts?.idempotencyKey);
|
|
704
716
|
if (existing) return { messageId: existing };
|
|
705
717
|
const messageId = MessageId.parse(`msg_${generateMessageId()}`);
|
|
706
718
|
testPump.push(QUEUE_PATHNAME, {
|
|
@@ -836,7 +848,9 @@ function parseSuccessEntity(outcome, key, schema) {
|
|
|
836
848
|
const value = outcome[key];
|
|
837
849
|
if (value === void 0) return void 0;
|
|
838
850
|
if (!isRecord(value)) malformedApplyEventOutcome(`${key} is invalid`);
|
|
839
|
-
const
|
|
851
|
+
const entity = compact(value);
|
|
852
|
+
if (key === "step") entity.error = value.error;
|
|
853
|
+
const result = schema.safeParse(entity);
|
|
840
854
|
if (!result.success) malformedApplyEventOutcome(`${key} is invalid`);
|
|
841
855
|
return result.data;
|
|
842
856
|
}
|
|
@@ -991,7 +1005,10 @@ function throwOutcomeError(outcome, runId, data) {
|
|
|
991
1005
|
}
|
|
992
1006
|
}
|
|
993
1007
|
const parseRun = (run) => WorkflowRunSchema.parse(compact(run));
|
|
994
|
-
const parseStep = (step) => StepSchema.parse(
|
|
1008
|
+
const parseStep = (step) => StepSchema.parse({
|
|
1009
|
+
...compact(step),
|
|
1010
|
+
error: step.error
|
|
1011
|
+
});
|
|
995
1012
|
const parseHook = (hook) => HookSchema.parse(compact(hook));
|
|
996
1013
|
const parseEvent = (event) => EventSchema.parse(compact(event));
|
|
997
1014
|
function unwrapRead(outcome) {
|