@DeadLetterQueue annotation enables automatic routing of failed events to a Dead Letter Queue backend. When a handler throws an exception — and all retries are exhausted if @RetryPolicy is present — the event is persisted in the DLQ instead of being silently lost.
The annotation itself is backend-agnostic: it carries only the cross-cutting policy (retention, payload flags) that every DLQ backend can honour. Backend-specific tuning (e.g. the MongoDB collection name) lives on a companion annotation such as @MongoDlqOptions.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Whether DLQ is enabled |
retentionDays | int | 30 | Retention in days. 0 means permanent (no expiry) |
includeOriginalDocument | boolean | true | Whether to include the original document in the DLQ entry |
includeStackTrace | boolean | true | Whether to include the full stack trace in the DLQ entry |
retentionDays
How long DLQ entries are retained before automatic cleanup. Each backend translates this to its native mechanism — the MongoDB backend sets a TTL index on the expiresAt field; Kafka maps it to retention.ms; RabbitMQ to the x-message-ttl header; JDBC to a scheduled cleanup job. Set to 0 to keep entries permanently.
includeOriginalDocument and includeStackTrace
These control what data is captured in the DLQ entry. Disabling them can reduce storage for high-throughput streams where you only need the error metadata.
Mongo-specific options: @MongoDlqOptions
@DeadLetterQueue deliberately does not carry the MongoDB collection name. Routing a stream’s failed events to a custom collection is a backend-specific concern, declared on the companion annotation @MongoDlqOptions:
| Attribute | Type | Default | Description |
|---|---|---|---|
collection | String | "" | MongoDB collection for this stream’s DLQ entries. Empty means use the global default. |
flowwarden.dlq.mongo.collection property (defaults to _fw_dlq). Streams without @MongoDlqOptions write to that collection.
@MongoDlqOptions has no effect when the configured DlqStore implementation is non-Mongo. Each backend ships its own companion annotation.expiresAt is created automatically at startup for every collection bound to a @DeadLetterQueue-annotated stream, so retentionDays takes effect without any manual index setup.
Storage
Failed events are persisted via theDlqStore SPI. The MongoDB-backed implementation (MongoDlqStore) is auto-configured by default and creates the expiresAt TTL index automatically at startup. Custom backends (Kafka, RabbitMQ, JDBC, …) plug in by declaring a @Bean DlqStore. The Redis satellite does not ship a DlqStore — Redis-backed deployments either keep the Mongo DLQ or supply a custom bean.
Roadmap
The following attributes are planned but not yet implemented:| Attribute | Description | Status |
|---|---|---|
reprocessStrategy | Automatic reprocessing strategy (MANUAL, AUTO_CRON) | Planned |
reprocessCron | Cron expression for automatic reprocessing | Planned |
reprocessBatchSize | Batch size for automatic reprocessing | Planned |
mongoTemplateRef | Custom MongoTemplate bean reference for multi-datasource setups (on @MongoDlqOptions) | Planned |
See Also
Retry & DLQ Guide
Understand DLQ routing, manual sends, document schema, and best practices
@RetryPolicy
Configure exponential backoff retry for failed handlers
@Checkpoint
Resume token persistence for reliable stream recovery
ChangeStreamContext
Runtime context including sendToDlq(), attempt number, and more