@ewhauser/world-celld 0.7.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 +26 -0
- package/README.md +5 -0
- package/dist/index.d.ts +15 -1
- 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-DzNOtCYA.d.ts → queue-delivery-wvPp6_Hh.d.ts} +30 -3
- package/dist/queue-delivery-wvPp6_Hh.d.ts.map +1 -0
- package/dist/{queue-protocol-CtH7UUCO.js → queue-protocol-C1zbXwa_.js} +28 -2
- package/dist/queue-protocol-C1zbXwa_.js.map +1 -0
- package/dist/{run-list-B__jKuE7.js → run-list-DGsdv6Jf.js} +28 -2
- package/dist/{run-list-B__jKuE7.js.map → run-list-DGsdv6Jf.js.map} +1 -1
- package/dist/testing.d.ts +2 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +945 -255
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +98 -1
- package/dist/worker.d.ts.map +1 -1
- package/dist/worker.js +972 -269
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/dist/queue-delivery-DzNOtCYA.d.ts.map +0 -1
- package/dist/queue-protocol-CtH7UUCO.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,32 @@
|
|
|
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
|
+
|
|
14
|
+
## 0.8.0 (2026-09-27)
|
|
15
|
+
|
|
16
|
+
## What's Changed
|
|
17
|
+
* test(perf): add a run-bearing mode to the MinIO queue benchmark by @ewhauser in https://github.com/ewhauser/world-celld/pull/78
|
|
18
|
+
* feat(queue): accept inline run-bearing Queue bodies at delivery by @ewhauser in https://github.com/ewhauser/world-celld/pull/79
|
|
19
|
+
* feat(queue): support run-scoped Queue idempotency claims by @ewhauser in https://github.com/ewhauser/world-celld/pull/81
|
|
20
|
+
* perf(queue): keep small run-bearing bodies inline in the broker by @ewhauser in https://github.com/ewhauser/world-celld/pull/80
|
|
21
|
+
* perf(queue): keep new runs' idempotency claims in the run cell by @ewhauser in https://github.com/ewhauser/world-celld/pull/82
|
|
22
|
+
* feat(streams): read, append, and expire segment-layout streams by @ewhauser in https://github.com/ewhauser/world-celld/pull/83
|
|
23
|
+
* perf(streams): store new streams in segment rows by @ewhauser in https://github.com/ewhauser/world-celld/pull/84
|
|
24
|
+
* chore(deps): bump zizmorcore/zizmor-action from 0.6.3 to 0.6.4 in the github-actions group across 1 directory by @dependabot[bot] in https://github.com/ewhauser/world-celld/pull/62
|
|
25
|
+
* test(smoke): keep the retention-restart Queue payload in object storage by @ewhauser in https://github.com/ewhauser/world-celld/pull/85
|
|
26
|
+
* Limit Dependabot to security updates by @ewhauser in https://github.com/ewhauser/world-celld/pull/63
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
**Full Changelog**: https://github.com/ewhauser/world-celld/compare/v0.7.0...v0.8.0
|
|
30
|
+
|
|
5
31
|
## 0.7.0 (2026-09-27)
|
|
6
32
|
|
|
7
33
|
## 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>>;
|
|
@@ -323,10 +328,19 @@ interface NativeQueueEnvelope {
|
|
|
323
328
|
runId?: string;
|
|
324
329
|
idempotencyKey?: string;
|
|
325
330
|
payloadKey?: string;
|
|
326
|
-
/**
|
|
331
|
+
/**
|
|
332
|
+
* Inline body. Health checks always travel inline; a run-bearing body may
|
|
333
|
+
* travel inline when it is small and carries no user data, in which case
|
|
334
|
+
* delivery checks the run's expiry instead of reading a payload object.
|
|
335
|
+
*/
|
|
327
336
|
body?: string;
|
|
328
337
|
/** Absolute workflow redelivery deadline; long waits are chained by the consumer. */
|
|
329
338
|
notBefore?: number;
|
|
339
|
+
/**
|
|
340
|
+
* Where the idempotency claim lives. Absent: the claim cell named by queue
|
|
341
|
+
* and key. `run`: an entry in the run's own cell (requires `runId`).
|
|
342
|
+
*/
|
|
343
|
+
claimScope?: 'run';
|
|
330
344
|
/** Failed deliveries carried across suspension re-publishes. */
|
|
331
345
|
deliveryFailures?: number;
|
|
332
346
|
suspensionCount?: number;
|
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) {
|