Dead letters
max_attempts with dead_letter becomes the consumer's own dead-letter policy: the client moves a spent message, and the service publishes nothing.
max_attempts(n) is how many times one message reaches the handler, the first delivery included.
dead_letter(topic) is where it goes once those are spent.
The Pulsar client counts the redeliveries, produces the spent message to that topic and acknowledges the original.
A retry, a retry_after and an expired ack_timeout each advance the count.
The two steps go together: a registration that writes one without the other refuses to start, and the error names the missing step.
The broker counts redeliveries only where consumers compete for messages, so the cap belongs to a Shared or a KeyShared subscription.
A registration that declares a cap over Exclusive or Failover refuses to start, and the error names the type.
A handler mounted by a bare topic name declares the same pair, and one policy covers every topic of a multi-topic subscription.
The client keeps the count to itself, so a handler cannot read how many deliveries a message has had.
Retries and dead letters caps the deliveries of a refunds service and reads its dead letters.
Example
- Macros
- Manual
#[ruststream::app]
fn app() -> impl App {
RustStream::new(AppInfo::new("bookkeeping", "0.1.0")).with_broker(
PulsarBroker::new("pulsar://localhost:6650"),
|b| {
// Three deliveries in all; then the client moves the payment to `payments-dlq`.
b.include(book)
.max_attempts(nonzero!(3))
.dead_letter("payments-dlq");
},
)
}
fn app() -> impl App {
RustStream::new(AppInfo::new("bookkeeping", "0.1.0")).with_broker(
PulsarBroker::new("pulsar://localhost:6650"),
|b| {
// Three deliveries in all; then the client moves the payment to `payments-dlq`.
b.include(subscriber(PulsarSubscription::new("payments", "bookkeeping"), Book).build())
.max_attempts(nonzero!(3))
.dead_letter("payments-dlq");
},
)
}