Skip to main content

Notification Consumers

Summary

Exactly one consumer exists: NotificationEventConsumer, a hosted BackgroundService registered at startup. It handles connection, declaration, binding, parsing, scoping and acknowledgement.

Audience

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

Reference Content

The verified reference material for this topic is set out in the sections below.

Registration and lifecycle

Registered as the only hosted service. Its execute loop runs until cancellation: it connects and begins consuming, then awaits indefinitely so the loop does not spin. A cancellation exits cleanly; any other exception is logged as a warning naming the broker host and port, and the loop retries after a fixed delay.

This means a broker outage produces repeated warning-level reconnect attempts rather than a crash or a failed health state — the service stays up and reports healthy while consuming nothing. See event limitations.

Per-delivery handling

For each delivery the consumer:

  1. Captures the channel reference and returns silently if it is null.
  2. Parses AMQP properties, headers and body into an envelope.
  3. Creates a new dependency-injection scope.
  4. Resolves the dispatcher from that scope and awaits dispatch.
  5. Acknowledges the single delivery tag.

The scope-per-delivery step is what gives each message its own scoped persistence context, preventing change-tracker state from leaking between messages.

Cancellation token usage

The consumer passes its stopping token — not a per-delivery token — into dispatch and acknowledgement. On shutdown, an in-flight dispatch is therefore cancelled mid-processing, which given the many-small-saves persistence model can leave a partially processed event with no idempotency ledger row.

Acknowledgement behavior

OutcomeAction
Dispatch completes without exceptionAcknowledge the delivery tag, not multiple
Any exception escapes dispatchLog as error, negatively acknowledge with requeue true
The negative acknowledgement itself failsLog as error and continue

There is no rejection without requeue and no bounded redelivery count, so a message that fails deterministically is requeued indefinitely. See retry and redelivery.

What counts as a failure

The dispatcher handles most business outcomes internally — duplicate, stale, no template, no recipient, suppressed and delivery failure all complete normally and are acknowledged. Only an infrastructure failure escaping the dispatcher, such as a persistence error, reaches the consumer's catch. The source comment states this intent directly.

Verified absence

There is no second consumer, no competing-consumer configuration in code, no consumer tag management, no manual channel recovery beyond the library's automatic recovery, and no concurrency limiter other than prefetch.

Classification

Implemented.

Requires confirmation

Whether shutdown should drain in-flight deliveries rather than cancel them requires confirmation.

See Also

Keywords

  • Notification database
  • Consumers
  • Draft database documentation

Source References

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

Revision Information

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