@talosjs/queue component is a background job layer built on BullMQ. You extend the abstract Queue base class, declare the data your jobs carry, and implement a handler that processes each job. Your subclass provides the BullMQ Queue and Worker; the base class wires the common producer helpers (add, addBulk, removeJob, close) and forwards worker lifecycle events to optional hooks on your class.
Producer and consumer in one class
ExtendingQueue<T, R> gives you typed add, addBulk, removeJob, and close methods, plus a worker that runs your handler once your subclass constructs it. The job data type T (a record of scalars) and the return type R flow through add and handler, keeping producers and consumers in sync. You can implement optional onCompleted, onFailed, onError, and other hooks, and the base class binds them to the worker when your subclass calls registerEvents(). Jobs persist in Redis through BullMQ, so they survive restarts and scale across worker instances. Register a queue class with a decorator and resolve it from the container.
How it works
A queue class extendsQueue<T, R>, where T extends Record<string, ScalarType> is the job data and R is the value the handler returns. Inside the constructor you create a BullMQ Queue (the producer) and a Worker (the consumer) over a shared Redis connection, then call registerEvents() to bind your hooks.
The producer side enqueues work:
The consumer side processes work. You implement the abstract
handler:
QueueHandlerReturnType<R> is Promise<R> | R, so the handler may be sync or async. The worker invokes it for each job and the returned value becomes the job result (surfaced to onCompleted).
Worker lifecycle events are optional hooks on IQueue. Declare any of them and registerEvents() attaches them:
Decorator and usage
@decorator.queue()
Registers a queue class with the container. It accepts an optional scope (defaults to singleton). Apply it to a class that extends Queue.
handler for each:
Exceptions
The package exportsQueueException as the typed error for queue-related failures in your own subclasses. The abstract Queue base class does not throw one on its own; you choose the keys and messages in the subclass that creates the BullMQ connection and worker.
Running queues well
Keep job data small and serializable. It’s a record of scalars (string, number, bigint, boolean), so pass ids and look up the rest in the handler rather than embedding large payloads. Make handlers idempotent too: jobs can be retried after a failure or a stall, so processing the same job twice has to be safe.
Always attach onError. Without it, worker-level errors go unhandled, so implement it (and usually onFailed) on every queue. Configure attempts with exponential backoff so flaky downstream calls recover instead of dropping the job, and use removeOnComplete and removeOnFail so finished jobs don’t pile up on a shared instance. Match concurrency and limiter to what the handler’s downstream resources can sustain. Finally, call close() on shutdown to drain the worker and release Redis connections cleanly.
CLI command
Scaffold a queue class and its test file with the generator. It writes the class undermodules/<module>/src/queues/<Name>Queue.ts and installs @talosjs/queue if it is missing.
The generated class builds the BullMQ
Queue and Worker from QUEUE_REDIS_URL, registers its event hooks, and leaves a handler for you to implement.
Use with Claude and Codex
The generator ships a matchingqueue:create skill. It runs the scaffold, then guides your AI agent through completing the queue: implementing handler, adding typed add/addBulk wrappers for the jobs it carries, and ensuring QUEUE_REDIS_URL is set. Initialize the skills once for your agent.
- Claude
- Codex
Prompt
queue:create --name=Email, then implements the handler to send each queued email.