Skip to content

MessageHistory

blehnen edited this page Nov 10, 2026 · 5 revisions

Message History

Message history tracks the lifecycle of every message after it leaves the queue: when it was enqueued, when processing started, whether it succeeded or failed, the exception if any, and how long it took.

After a message is committed or deleted, it is gone from the queue tables. History gives you an audit trail, so you can answer "what happened to message X last Tuesday?"

Enabling history

History has two parts: the history table (created once) and runtime tracking (enabled per consumer).

Step 1: Create the queue with history enabled

Set EnableHistory = true on the transport options when creating the queue:

using (var creator = new QueueCreationContainer<SqLiteMessageQueueInit>())
{
    using (var creation = creator.GetQueueCreation<SqLiteMessageQueueCreation>(queueConnection))
    {
        creation.Options.EnableStatus = true;
        creation.Options.EnableStatusTable = true;
        creation.Options.EnableHistory = true;  // creates the history table
        var result = creation.CreateQueue();
    }
}

If the queue already exists without a history table, you need to recreate the queue or create the history table manually.

Step 2: Enable history on the consumer

Set Enabled = true on the consumer configuration before starting:

using (var consumer = queueContainer.CreateConsumer(queueConnection))
{
    consumer.Configuration.History.Enabled = true;
    consumer.Configuration.History.RetentionDays = 30;
    consumer.Configuration.History.StoreBody = false;
    consumer.Configuration.History.MaxExceptionLength = 4000;

    consumer.Start<MyMessage>((message, notification) =>
    {
        // process message
    }, notifications);
}

The consumer tracks processing start, complete, error, rollback, delete, and expire events.

Note: Enqueue tracking on the producer side also requires IHistoryConfiguration.Enabled = true in the producer's container. If you enable it only on the consumer, the library does not record enqueue events. It still records processing, complete, and error events.

What gets tracked

Each message has one history record. The library updates the record as the message moves through the lifecycle states:

Status When recorded
Enqueued Message sent by producer
Processing Consumer dequeues the message
Complete Handler finishes and message is committed
Error Handler throws and message moves to error status
Deleted Message is deleted
Expired Message expires before being processed

A rollback increments a retry counter and resets the status to Enqueued.

History record fields
Field Description
QueueId The message's queue identifier
CorrelationId Cross-system correlation ID from headers
Status Current lifecycle status
EnqueuedUtc When the message was added to the queue
StartedUtc When processing began
CompletedUtc When processing finished (success, error, or delete)
DurationMs Processing time in milliseconds
ExceptionText Truncated exception for error status
RetryCount Number of retries before final status
Route Message route, if routing is enabled
MessageType Body type name from header
Body Serialized body bytes (only when StoreBody = true)
Headers Serialized header bytes (only when StoreBody = true)
Body storage

By default, history does not store the message body. It is an audit trail, not a backup. Set StoreBody = true to store the serialized body and headers with each history record. This lets the dashboard show the body for completed messages. It also increases storage on high-throughput queues.

The error table already keeps the bodies of error messages. Thus the most common debugging case does not need body storage.

Retention and purge

A ClearHistoryMonitor runs periodically (default: once per day) and deletes records older than RetentionDays (default: 30). It works the same way as the error message cleanup monitor. It runs as part of the maintenance monitors with both MaintenanceMode.Consumer and MaintenanceMode.External.

Configuration reference
Setting Default Description
Enabled false Enable history tracking
RetentionDays 30 Days to keep history before purging
MaxExceptionLength 4000 Truncate exception text to this length
StoreBody false Store serialized message body and headers
MonitorTime 1 day How often the purge monitor runs
TrackEnqueue true Record when messages are enqueued
TrackProcessing true Record when processing starts
TrackComplete true Record when processing succeeds
TrackError true Record when processing fails
TrackDelete true Record when messages are deleted
TrackExpire true Record when messages expire
Dashboard

The Dashboard API exposes history data through these endpoints:

  • GET /api/v1/dashboard/queues/{queueId}/history: paged list with optional status filter
  • GET /api/v1/dashboard/queues/{queueId}/history/{messageId}: single message history
  • GET /api/v1/dashboard/queues/{queueId}/history/count: count with optional filter
  • DELETE /api/v1/dashboard/queues/{queueId}/history: purge by age

The Dashboard UI has a History tab on the queue detail page with status filtering, color-coded status chips, duration formatting, expandable exception text, and a purge button.

Transport support

History is implemented for all 6 transports: SQL Server, PostgreSQL, SQLite, LiteDB, Redis, and Memory.

Clone this wiki locally