Concepts
Jobs
Jobs are first-class values created with createJob. They carry their name, input schema, handler, and optional hooks as a single object.
createJob
import { createJob } from '@repo/queue'
import { z } from 'zod'
export const sendEmailsJob = createJob({
name: 'send-emails',
input: z.object({
email: z.string().email(),
subject: z.string(),
body: z.string(),
}),
dedupeKey: (payload) => `email:${payload.email}:${payload.subject}`,
handler: async ({ email, subject, body }, ctx) => {
// payload is fully typed from the input schema
},
})Parameters
| Field | Type | Description |
|---|---|---|
name | string | Unique job identifier |
input | StandardSchemaV1 | Schema defining the payload shape (Zod, Valibot, etc.) |
dedupeKey | string | function | Optional default dedupe key, static or derived from the typed payload |
handler | (payload, ctx?) => Awaitable<TResult> | Function that processes the job |
hooks | JobHooks | Optional lifecycle hooks |
Payload Typing
The payload argument in handler is inferred from the input schema. No manual type annotations needed -- the schema is the single source of truth for both runtime validation and TypeScript types.
Context (BaseJobCtx)
The second argument to handler provides execution context:
interface BaseJobCtx {
jobId: string
queue: string
attempt: number // 1-based
maxAttempts?: number
signal: AbortSignal
meta?: Record<string, unknown>
session?: Session // auth session from dispatch time
log: Logger
}Hooks
Hooks run after the handler completes (or fails). All hooks are optional.
export const sendEmailsJob = createJob({
name: 'send-emails',
input: z.object({/* ... */}),
handler: async (payload, ctx) => {
/* ... */
},
hooks: {
onError: (err, payload, ctx) => {
// called on every failed attempt
},
onFailed: (err, payload, ctx) => {
// called only on the final attempt (all retries exhausted)
},
onSuccess: (result, payload, ctx) => {
// called when handler returns successfully
},
},
})Hook Signatures
interface JobHooks<TPayload, TResult, TCtx> {
onError?: (err: TResult, payload: TPayload, ctx: TCtx) => Awaitable<void>
onFailed?: (err: TResult, payload: TPayload, ctx: TCtx) => Awaitable<void>
onSuccess?: (result: TResult, payload: TPayload, ctx: TCtx) => Awaitable<void>
}- onError -- fires on every failed attempt, including retries
- onFailed -- fires only when
attempt >= maxAttempts(final failure) - onSuccess -- fires when the handler resolves without throwing
Hooks can also be defined globally on the runtime. See Runtime.