In many IoT deployments, devices push data faster than backend REST APIs can ingest them. Traditional "fire-and-forget" MQTT subscribers often suffer from:
-
Backpressure: Slow API responses cause the MQTT subscriber to lag, eventually dropping connections.
-
Data Loss: Messages are overwritten or lost during network partitions.
-
Lack of Observability: No way to track which specific messages failed or to re-run them.
This project implements a Resilient Subscriber Pattern using .NET Background Workers. It acts as a high-speed buffer between an ESP32 sensor array and a legacy REST API.
-
Non-Blocking Ingestion: Uses
System.Threading.Channelsto decouple MQTT reception from processing. -
Local Persistence: Every message is "Staged" in a local LiteDB instance before transmission.
-
Circuit Breaker Pattern: Automatically halts API traffic during downstream outages to prevent system exhaustion.
-
Self-Healing: An "Outbox" worker identifies unprocessed records and retries them with exponential backoff.
[!TIP] This architecture ensures that even if the REST API is down for hours, no data is lost as long as the local disk has space.
The core of your solution relies on decoupling. Instead of a direct pipe where the MQTT subscriber is blocked by the REST API's response time, you are creating a "Buffer and Forward" system.
-
Ingestion: The
.NET Background Workersubscribes to Mosquitto. -
Internal Handoff: It pushes the message into a
System.Threading.Channels(Bounded Channel). This allows the MQTT thread to return immediately, keeping the broker connection healthy. -
Persistence (The "Safety Net"): A consumer reads from the channel and writes the raw JSON to the LiteDB/SQLite database immediately.
-
The Circuit Breaker: Using Polly, if the REST API starts failing or slowing down (latency > X ms), the Circuit Breaker opens.
-
Offline Mode: While the circuit is open, the system continues to save to the DB but stops attempting the API calls, preventing a backlog of "zombie" requests.
-
Reprocessing: A separate worker polls the DB for
isProcessed = falserecords and attempts to sync them once the API is healthy.
| Component | Recommendation | Why? |
|---|---|---|
| Edge Device | ESP32 (C++ / Arduino) | More performant for high-frequency MQTT than nanoFramework in most "real-time" scenarios. |
| Local Database | LiteDB | Excellent for .NET; it’s a NoSQL document store that is "serverless" (file-based) like SQLite, but handles JSON natively. |
| Resilience | Polly v8 | Use the new "Resilience Pipelines" for combining Retries and Circuit Breakers. |
| Communication | Refit | Keeps your REST client code clean and interface-based. |
-
TLS (Transport Layer Security): Encrypts the data while it is moving between the ESP32 and Mosquitto. It prevents "Eavesdropping."
-
Digital Signature (Application Level): Protects the data while it is "at rest" in your LiteDB and during the REST API hop. It prevents "Tampering."
-
The ESP32 will need the
ca.crtto verify it's talking to the right broker. -
The .NET Worker will use the
client.crtandclient.keyif you decide to enforce mutual TLS (mTLS), or just theca.crtfor a standard encrypted connection.
- The broker is configured to support secure MQTT communication over TLS with mutual TLS (mTLS), leveraging a private Certificate Authority and X.509 certificates.