Queue jobs (messaging)
Provider-agnostic queue handlers — QueueBase, IQueueService, and infra stub.
Opt-in: install with
kl-nest new (multiselect) or kl-nest add queue. On a Worker, this is usually the main feature (kl-nest new my-worker -y --type worker --features queue). Does not install JobsModule / host/jobs — use QueueBase + IQueueService.
This feature copies broker-agnostic bases (Cloudflare Queues, SQS, RabbitMQ, etc.). You implement the infra adapter later; the consume loop and port are ready.
| Artifact | Role |
|---|---|
QueueBase |
Pull loop with concurrency, Zod validation, ack/retry |
IQueueService |
Domain port (push / pull / ack / retry / isConfigured) |
QueueService |
Infra stub — methods throw until you replace them |
QueueFakeService |
In-memory fake for tests |
Environment variables
When the feature is installed, the CLI injects into env.ts / .env.example / .env. Defining them in .env is optional — the Zod schema applies defaults if the keys are missing. QueueBase reads these via EnvService (do not pass them in the constructor).
| Variable | Default | Usage |
|---|---|---|
QUEUE_MAX_CONCURRENCY |
10 |
Parallel slots in QueueBase |
QUEUE_CAPACITY_DELAY_MS |
200 |
Wait when no free slots |
QUEUE_IDLE_DELAY_MS |
1000 |
Wait when the queue is empty |
QUEUE_ERROR_DELAY_MS |
2000 |
Backoff after a loop error |
No provider-specific variables (Cloudflare IDs, SQS credentials, etc.) — those belong in your IQueueService implementation.
Create a handler
- Define the message DTO +
RequestValidatorBase. - Extend
QueueBase<TMessage>and implementprocessMessage. - Pass only
queueNameinqueueOptions— concurrency and delays come from env:
typescript
@Injectable()
export class ConsumeExampleQueueHandler extends QueueBase<ExampleMessageDto> {
constructor(queue: IQueueService, env: EnvService) {
super(queue, env, {
loggerName: ConsumeExampleQueueHandler.name,
validator: ExampleMessageValidator,
queueOptions: {
queueName: QueueName.example,
},
});
}
protected async processMessage(message: ExampleMessageDto): Promise<void> {
// business logic
}
}
- Register the handler in the feature module and call
start()during bootstrap (main.tsor anOnModuleInitservice). - Replace
QueueServicewith a real adapter inInfraModule({ provide: IQueueService, useClass: MyAdapter }).
Tests
Use QueueFakeService in unit/integration tests: enqueue, push/pull/ack/retry, and setConfigured(false) to simulate an unconfigured queue.