Skip to content

Log an error when an exception bypasses the dead letter queue - #354

Draft
nabisobhi wants to merge 1 commit into
masterfrom
nabisobhi-dlq-observability
Draft

Log an error when an exception bypasses the dead letter queue#354
nabisobhi wants to merge 1 commit into
masterfrom
nabisobhi-dlq-observability

Conversation

@nabisobhi

Copy link
Copy Markdown
Contributor

Stacked on #353 — please review that one first. This PR''s diff is against nabisobhi-bookish-waddle, so it shows only the logging change.

Why

#353 lets registered exception types bypass the dead letter queue and propagate, crashing the consumer. Until now that happened silently from the Consumer''s point of view — there was no record of why the consumer died or which message triggered it.

Change

Consumer now takes an optional ILogger<Consumer> (defaulting to NullLogger<Consumer>.Instance, so existing call sites and tests are unaffected) and logs before rethrowing:

Exception of type {ExceptionType} bypassed the dead letter queue for message with key {Key} from topic {SourceTopic}. Failing the consumer

Logged at Error level with the exception attached. The real logger is resolved in both AddConsumer overloads.

To log at that point, the bypass check moved out of the exception filter into the catch body, which now rethrows with a bare throw;. That preserves the original stack trace, and behavior is otherwise identical.

Overlap worth a reviewer''s opinion

ConsumerHostedService.ConsumeAll already logs any escaping exception as "Unhandled error occurred while consuming messaging", so a bypassed exception will now produce two Error entries: this context-rich one, then the generic boundary one. That''s a common pattern (detail at the site, generic at the boundary), but if you''d rather avoid the duplication, options are to drop this to Warning or skip this PR entirely — #353 is fully functional without it.

Notes

  • No new NuGet dependencies; Microsoft.Extensions.Logging.Abstractions is already referenced.
  • No public API changeConsumer is internal.
  • Added LoggerSpy<T> test double rather than Mock<ILogger<Consumer>>, because Moq can''t proxy a generic closed over an internal type without InternalsVisibleTo("DynamicProxyGenAssembly2").

Tests

Two new tests: the bypass logs the expected level/exception/message, and dead-lettered messages do not log the bypass error. TestConsumer 37/37, full suite 156/156, build clean with 0 warnings.

@nabisobhi
nabisobhi marked this pull request as draft August 30, 2026 18:56
Base automatically changed from nabisobhi-bookish-waddle to master September 10, 2026 12:22
Consumer now accepts an optional ILogger<Consumer> (defaulting to NullLogger) and logs an error with the exception type, partition key and source topic when a registered bypass exception is about to propagate and crash the consumer. The real logger is resolved in both AddConsumer overloads.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@nabisobhi
nabisobhi force-pushed the nabisobhi-dlq-observability branch from ce37df9 to 47df637 Compare September 10, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant