MonoStack
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

FieldTypeDescription
namestringUnique job identifier
inputStandardSchemaV1Schema defining the payload shape (Zod, Valibot, etc.)
dedupeKeystring | functionOptional default dedupe key, static or derived from the typed payload
handler(payload, ctx?) => Awaitable<TResult>Function that processes the job
hooksJobHooksOptional 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.

On this page