Course contentsShow
← C#
Lesson 1560 of 1,90814. Background Work and MessagingFree lesson

Handling Large Payload Transfers

Manage scenarios where event payloads exceed message broker limits using the Claim Check pattern.

In this lesson, you will learn how to bypass message broker size limits using the Claim Check pattern to reliably transfer massive data payloads in your distributed system.

The Problem: The "Payload Ceiling"

Message brokers (like RabbitMQ, Azure Service Bus, or Kafka) are designed for lightweight signaling. They perform poorly—or fail entirely—when asked to carry megabytes of binary data or massive JSON arrays. Most brokers enforce hard size limits (often 256KB to 1MB). Trying to shove a 50MB file through a broker not only causes errors but also destroys the throughput of your entire messaging infrastructure by consuming excessive memory and IO.

The Solution: The Claim Check Pattern

Instead of putting the large payload directly into the message, we "offload" the data to a durable, high-throughput storage medium—such as Azure Blob Storage, AWS S3, or a shared database.

The process follows three steps:

  1. Store: The producer saves the large payload to external storage.
  2. Issue: The producer sends a lightweight message to the broker containing only the metadata and a ClaimCheckId (the URI or ID of the stored object).
  3. Redeem: The consumer receives the message, uses the ClaimCheckId to fetch the actual payload from the storage, and processes it.

Practical Implementation

When building this in C#, your message schema changes from holding the raw data to holding a reference:

public record LargeDataMessage(
    Guid CorrelationId, 
    string ClaimCheckId, // The URI to the blob
    DateTime Timestamp
);

When your background worker consumes this, it handles the retrieval:

public async Task HandleAsync(LargeDataMessage message)
{
    // Retrieve the actual large data from a repository or blob service
    var largePayload = await _blobStorage.DownloadAsync(message.ClaimCheckId);
    
    // Process the data as if it were local
    await _processor.ExecuteAsync(largePayload);
    
    // Optional: Delete the claim check after processing to save costs/space
    await _blobStorage.DeleteAsync(message.ClaimCheckId);
}

This approach maintains the decoupling of your messaging architecture while ensuring your broker only handles the "envelope," leaving the "contents" to storage services optimized for large-scale data persistence.

Key Takeaway: When your payload exceeds the broker's capacity, store the data in an external repository and pass only the reference through the message bus to keep your event streams performant.