Skip to content

Commit e09f19d

Browse files
committed
Polish task enqueue path and queue-isolation docs
Small follow-ups from review: - Document that tasks must be defined before startQueue() (or the first request); workers for dedicated per-task queues are only registered when the queue machinery starts, so a queue defined later never gets a worker. - Return early from the enqueue path when no payloads are given, instead of reaching enqueueMany()/Promise.all with an empty batch, whose backend behavior is undefined. - Rename #enqueueSingular to #encodeTaskMessage; it encodes and builds a TaskMessage but does not enqueue anything. - Fix a comment typo in the codec. fedify-dev#803 Assisted-by: Claude Code:claude-fable-5
1 parent f88c0b5 commit e09f19d

4 files changed

Lines changed: 32 additions & 3 deletions

File tree

docs/manual/tasks.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,12 @@ const transcodeVideo = federation.defineTask("transcodeVideo", {
215215
});
216216
~~~~
217217

218+
Workers for dedicated per-task queues are registered when the queue
219+
machinery starts, so define every task before `~Federation.startQueue()`
220+
is called (or, without `~FederationOptions.manuallyStartQueue`, before the
221+
first request is handled); a per-task queue defined later never gets
222+
a worker.
223+
218224
The queue for a task is resolved in order: the per-task `queue`, then the
219225
federation's `task` queue, then the outbox queue. Deployments that must
220226
*not* silently share the outbox queue can opt out of the last step with

packages/fedify/src/federation/middleware.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3680,6 +3680,7 @@ export class ContextImpl<TContextData> implements Context<TContextData> {
36803680
"createFederation() or to defineTask().",
36813681
);
36823682
}
3683+
if (items.length < 1) return;
36833684
const delay = options.delay == null
36843685
? undefined
36853686
: Temporal.Duration.from(options.delay);
@@ -3688,7 +3689,7 @@ export class ContextImpl<TContextData> implements Context<TContextData> {
36883689
// `map` preserves order, and a rejected encode (validation failure) rejects
36893690
// the whole batch before anything is enqueued, keeping fail-fast intact.
36903691
const messages: TaskMessage[] = await Promise.all(
3691-
items.map(this.#enqueueSingular(task, options)),
3692+
items.map(this.#encodeTaskMessage(task, options)),
36923693
);
36933694
const enqueueOptions = { delay, orderingKey: options.orderingKey };
36943695
if (messages.length === 1) {
@@ -3700,7 +3701,7 @@ export class ContextImpl<TContextData> implements Context<TContextData> {
37003701
}
37013702
}
37023703

3703-
#enqueueSingular = <TData>(
3704+
#encodeTaskMessage = <TData>(
37043705
task: TaskDefinition<TContextData, TData>,
37053706
options: TaskEnqueueOptions,
37063707
) =>

packages/fedify/src/federation/tasks/codec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default class TaskCodec {
4343
if (node === null || typeof node !== "object") return node;
4444
if (seen.has(node)) return seen.get(node);
4545
const reviver = this.#classRevivers.find(([filter]) => filter(node));
46-
// devalue can handled non-container objects.
46+
// devalue can handle non-container objects.
4747
if (reviver == null) return node;
4848
const [, init, set] = reviver;
4949
// @ts-ignore tsc faults

packages/fedify/src/federation/tasks/tasks.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,28 @@ test("Context.enqueueTask() end-to-end", async (t) => {
399399
strictEqual(queue.enqueued.length, 2);
400400
},
401401
);
402+
403+
await t.step(
404+
"enqueueTaskMany() with no payloads touches no queue",
405+
async () => {
406+
const queue = new MockQueue({ supportsEnqueueMany: true });
407+
const federation = createFederation<void>({
408+
...baseOptions,
409+
queue: { task: queue },
410+
});
411+
const task = federation.defineTask("bulk-empty", {
412+
schema: stringSchema,
413+
handler: () => {},
414+
});
415+
const ctx = federation.createContext(
416+
new URL("https://example.com/"),
417+
undefined,
418+
);
419+
await ctx.enqueueTaskMany(task, []);
420+
strictEqual(queue.enqueued.length, 0);
421+
strictEqual(queue.enqueuedMany.length, 0);
422+
},
423+
);
402424
});
403425

404426
test("task queue routing", async (t) => {

0 commit comments

Comments
 (0)