Skip to main content

Notification Retry and Redelivery

Summary

Two independent retry mechanisms exist and they operate at different layers: a bounded in-process delivery retry inside the dispatcher, and an unbounded broker requeue in the consumer.

Audience

Engineers, architects, QA, support, DevOps engineers and security reviewers.

Retry and redelivery

Layer one — in-process delivery retry

Owned by the retry policy and driven by the dispatcher. Bounded by a configurable maximum attempt count defaulting to 3, with an exponential delay computed as the base delay multiplied by the backoff factor raised to the attempt index; attempt one has no delay. Defaults are 200 milliseconds and a factor of 2.

Each attempt writes an attempt row. Exhausting attempts marks the message failed and audits it — and completes normally. A permanently undeliverable notification therefore does not cause the event to be requeued.

Delays are awaited in process, so the broker delivery stays un-acknowledged for the whole retry sequence, and a cancellation during a delay stops the loop.

Layer two — broker redelivery

Owned by the consumer. Any exception escaping dispatch is logged and the delivery is negatively acknowledged with requeue set to true.

This is intended for infrastructure faults — the source comment names a database outage — where retrying later is right.

Unbounded requeue

There is no delivery-count check, no redelivery-limit header inspection, no rejection without requeue and no bounded attempt tracking at the consumer layer.

A message that fails deterministically — a payload that reliably breaks persistence, or the unique-violation path described in idempotency — is requeued indefinitely. Because the queue has no dead-letter arguments, there is nowhere for it to go. The result is a hot loop bounded only by how fast the broker redelivers, visible as repeated error logs.

This is the most operationally significant event limitation in the module.

Interaction with idempotency

Requeue and idempotency partly compensate. If the failure happened after the ledger row was written, redelivery is suppressed as a duplicate and acknowledged. If it happened before — which is the common case, since the ledger is written last — redelivery reprocesses fully.

Manual retry

A separate, operator-driven path re-drives one message by identifier through the same bounded loop. It does not involve the broker and is documented in the API and database sections.

Verified absence

No retry queue, no delay queue, no scheduled redelivery, no exponential backoff at the broker layer, no circuit breaker, no poison-message quarantine and no maximum-redelivery policy exists in the reviewed source.

Classification

Foundation — bounded delivery retry is Implemented; broker-layer redelivery control is Not implemented.

Requires confirmation

Whether a redelivery limit and poison-message handling are planned requires confirmation.

See Also

Keywords

  • Notification database
  • Retry & Redelivery
  • Draft database documentation

Source References

  • microservices/src/notification-service/Application/NotificationDispatcher.cs
  • microservices/src/notification-service/Application/RetryPolicy.cs
  • microservices/src/notification-service/Messaging/NotificationEventConsumer.cs
  • microservices/src/notification-service/Application/NotificationOptions.cs

Revision Information

  • Status: Draft
  • Last reviewed: 2026-07-21
  • Review cycle: Quarterly