Course contentsShow
← C#
Lesson 1499 of 1,90813. Real-time Communication with SignalRFree lesson

Distributed Message Ordering

Ensure message sequence integrity across multiple network hops and asynchronous buffers.

In this lesson, you will learn how to maintain strict causal order for messages traversing asynchronous buffers and distributed network hops in a SignalR architecture.

The Challenge of Distributed Ordering

When you send messages through SignalR—especially when routed through an Azure SignalR Service or a load-balanced cluster—the "first-in, first-out" (FIFO) guarantee of a single TCP connection is broken. Because messages can traverse different internal buffers, experience varying network latency, or be retried across different Hub instances, the client might receive Message B before Message A, even if A was sent first.

Implementing Sequence Anchoring

To solve this, we introduce Sequence Anchoring. Each message must carry a strictly increasing metadata identifier (like a long sequence number or a Guid with a timestamp).

Rather than processing every message the moment it arrives, the client maintains a Reorder Buffer. When a message arrives, the client checks if its sequence number is exactly one greater than the last processed message.

public class MessageEnvelope {
    public long SequenceNumber { get; set; }
    public string Payload { get; set; }
}

// Client-side buffer logic
private long _lastProcessedSeq = 0;
private SortedList<long, MessageEnvelope> _buffer = new();

public void OnMessageReceived(MessageEnvelope msg) {
    if (msg.SequenceNumber == _lastProcessedSeq + 1) {
        Process(msg);
        _lastProcessedSeq = msg.SequenceNumber;
        // Check buffer for subsequent messages that arrived early
        FlushBuffer();
    } else {
        _buffer[msg.SequenceNumber] = msg;
    }
}

Navigating Asynchronous Buffers

In a distributed system, you cannot rely on the server to "hold" messages for the client. The server acts as a pass-through; therefore, the responsibility of ordering shifts to the edge. If the client receives Sequence 5 but its last processed message was 3, it must store 5 in the buffer and wait for 4.

If 4 does not arrive within a specific timeout window, the client must trigger a resynchronization request—a concept we touched upon in our "Offline-to-Online Synchronization" lessons—to fetch the missing sequence directly from the source of truth, ensuring the state remains consistent despite the inherent non-determinism of distributed network transport.

Key Takeaway: In distributed systems, ignore arrival time and enforce logical ordering by tagging messages with sequence identifiers and processing them through a client-side reorder buffer.