Skip to main content

On This Page

Building Scalable Multi-Channel Notification Services with .NET 8 and RabbitMQ

2 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Building a Multi-Channel Notification Service in .NET 8

This architecture implements a complete notification service in .NET 8 capable of delivering messages across Email, SMS, and Push channels. By utilizing a RabbitMQ topic exchange, it decouples delivery logic from the main application to prevent API latency spikes caused by slow downstream providers.

Why This Matters

In ideal models, sending a notification is a simple API call, but technical reality involves slow SMTP providers, Twilio rate limits, and downstream outages that can crash an entire API. Decoupling delivery using an asynchronous worker pattern ensures that one failing provider never blocks another and allows for per-channel rate limiting and independent scaling to handle production-grade traffic spikes without silent message loss.

Key Insights

  • RabbitMQ Topic Exchanges route messages based on priority headers, ensuring critical notifications bypass lower-priority traffic (2024 architecture).
  • Scriban template engine provides a sandboxed AST for safe, high-performance string interpolation without the security risks of arbitrary code execution (Scriban 2024).
  • Sliding window rate limiting implemented via IMemoryCache or Redis prevents recipient flooding and manages external provider costs.
  • Parallel fan-out dispatch using Task.WhenAll allows concurrent delivery across Email (MailKit), SMS (Twilio), and Push (Firebase) channels.
  • Dead-letter queues (DLQ) capture failed delivery attempts after 3 retries, preventing permanent data loss during downstream outages.

Working Examples

RabbitMQ Publisher implementation with message persistence and priority routing.

public async Task PublishAsync(NotificationRequest request, CancellationToken ct = default) { var body = JsonSerializer.SerializeToUtf8Bytes(request); var props = _channel!.CreateBasicProperties(); props.Persistent = true; props.Priority = (byte)request.Priority; _channel.BasicPublish(exchange: _opts.ExchangeName, routingKey: $"notification.{request.Priority.ToString().ToLower()}", basicProperties: props, body: body); }

Parallel fan-out orchestration in the Dispatcher service.

public async Task DispatchAsync(NotificationRequest request, CancellationToken ct = default) { var targets = channels.Where(c => request.Channels.Contains(c.ChannelName, StringComparer.OrdinalIgnoreCase)).ToList(); var tasks = targets.Select(ch => SendToChannelAsync(ch, request, recipient, ct)); await Task.WhenAll(tasks); }

Practical Applications

  • Use Case: E-commerce systems dispatching concurrent order confirmations via Email and Push using Task.WhenAll. Pitfall: Sequential processing where one slow provider delays the entire notification chain.
  • Use Case: Authentication services implementing sliding window rate limits to prevent SMS OTP flooding. Pitfall: Global rate limits that block all users instead of per-recipient targeting.
  • Use Case: High-security environments using Scriban for user-editable templates. Pitfall: Using Razor templates which allow execution of arbitrary C# code in the rendering engine.

References:

Continue reading

Next article

Provisioning AWS Networking with Terraform: A Hands-on Infrastructure as Code Guide

Related Content