Skip to main content
The @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

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:
The global default for the collection name is configured by the 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.
The MongoDB TTL index on 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 the DlqStore 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:

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