Skip to content

Job Blockers

Jobs can depend on other job chains to complete before they start. A job with incomplete blockers starts as blocked and transitions to pending when all blockers complete.

const jobTypeRegistry = defineJobTypeRegistry<{
"fetch-data": {
entry: true;
input: { url: string };
output: { data: string };
};
"process-all": {
entry: true;
input: { ids: string[] };
output: { results: string[] };
blockers: [{ typeName: "fetch-data" }, ...{ typeName: "fetch-data" }[]]; // Wait for multiple fetches (tuple with rest)
};
}>();
// Start with blockers (transactionHooks required — see Transaction Hooks guide)
const fetchBlockers = await withTransactionHooks(async (transactionHooks) =>
client.startJobChains({
transactionHooks,
items: [
{ typeName: "fetch-data", input: { url: "/a" } },
{ typeName: "fetch-data", input: { url: "/b" } },
],
}),
);
await withTransactionHooks(async (transactionHooks) =>
client.startJobChain({
transactionHooks,
typeName: "process-all",
input: { ids: ["a", "b", "c"] },
blockers: fetchBlockers,
}),
);
// Access completed blockers in worker
const worker = await createInProcessWorker({
client,
jobTypeProcessorRegistry: createJobTypeProcessorRegistry({
client,
jobTypeRegistry,
processors: {
"process-all": {
attemptHandler: async ({ job, complete }) => {
const results = job.blockers.map((b) => b.output.data);
return complete(() => ({ results }));
},
},
},
}),
});
const stop = await worker.start();

The example above uses nominal references{ typeName: "fetch-data" }. Blockers also support fixed tuple slots, variadic rest slots, and structural references ({ input: {...} }) that match any entry job type with a compatible input shape. Blocker outputs are fully typed in the processor based on the reference. See Job Type References for details and examples.

See examples/showcase-blockers for a complete working example demonstrating fan-out/fan-in and fixed blocker slots. See also Transaction Hooks and Chain Patterns.