Workhorse
Executing work

Batch handlers

Process several jobs of one type through a shared application call while preserving per-job outcomes.

Use TypeScript's Worker.handleBatch, Go's Worker.HandleBatch, or Python's Worker.handle_batch when one application call can process several jobs more efficiently. Each member keeps its own durable identity, lease, fence, retry budget, checkpoints, progress, and cancellation.

worker.handleBatch("email.send", { maxSize: 20, lingerMs: 50 }, async (items) => {
  const deliveries = await emailProvider.sendMany(items.map((item) => item.payload));
  return deliveries.map((delivery) =>
    delivery.error
      ? { status: "failed", error: delivery.error }
      : { status: "succeeded", result: { providerId: delivery.id } },
  );
});

maxSize caps the group, while lingerMs lets a partial group wait briefly for peers. Claims still pass through normal priority, queue, concurrency, keyed, and rate-limit admission, so a group can remain partial until its linger ends.

The callback returns one ordered outcome per member. If it throws or returns an invalid list, Workhorse submits the failure for every member, then each job applies its own retry policy.

Python passes max_size and linger_ms as keyword arguments. Its callback returns mappings with the same succeeded and failed statuses. Each item carries a BatchHandlerContext with get_progress and set_progress.

Go passes MaxSize and Linger through BatchHandlerOptions. Its callback returns positional BatchSucceeded or BatchFailed values, and each item carries a BatchHandlerContext with its standard cancellation context, checkpoint operation, GetProgress, and SetProgress.

Workhorse records each shared invocation before the callback starts. The task drawer shows the batch size and links the other members. If the shared callback fails, the drawer identifies that failure across the group instead of guessing from the individual task errors.

Batch contexts omit timers, signals, human waits, and child joins because one member cannot suspend and replay independently inside a shared invocation. Register an ordinary handler when a job needs those boundaries.

TypeScript configures grouping with BatchHandlerOptions.maxSize and BatchHandlerOptions.lingerMs; each option changes assembly of the batch without changing an individual job's lifecycle.

Next

  • Workers — size the capacity that batch members occupy
  • Priority — order members before grouping
  • Retries — apply failures per member

Exact batch limits and lifecycle rules: architecture reference.

On this page