Repository navigation
MessageHistory
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?"
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.
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.
| 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) |
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.
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.
| 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 |
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.
History is implemented for all 6 transports: SQL Server, PostgreSQL, SQLite, LiteDB, Redis, and Memory.
For any issues please use the GitHub issues