Getting Started
Architecture
NServiceBus
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Discarding expired messages

Component: MSMQ Transport
NuGet Package: NServiceBus.Transport.Msmq (1.2)
Target Version: NServiceBus 7.x

The MSMQ transport can handle messages with a Time-To-Be-Received (TTBR) set in two ways.

Native

When a message with a TTBR value is sent, NServiceBus translates the value to the native TTBR property of the MSMQ message. MSMQ continuously checks the Time-To-Be-Received of all queued messages. As soon as the message has expired, it is removed from the queue, and disk space gets reclaimed.

MSMQ enforces a single Time-To-Be-Received value for all messages in a transaction. If multiple messages enlist in a single transaction, then the TTBR from the first message will be used for all messages, leading to potentially unintentional message expiration. To prevent message loss, TTBR is not supported for endpoints with transaction mode SendsAtomicWithReceive or TransactionScope by default.

The MSMQ native TTBR implementation can be disabled for messages sent as part of a transaction. These messages rely on the non-native TTBR handling to ensure they are discarded when they are read by an endpoint, if the time to be received has expired. Messages sent outside of a transaction will still use the native TTBR capabilities built into the transport.

var transport = endpointConfiguration.UseTransport<MsmqTransport>();
transport.DisableNativeTimeToBeReceivedInTransactions();
Messages sent without the native MSMQ TTBR property set cannot automatically be cleaned up by MSMQ. They will remain in a queue until they are read. If they are read by an endpoint running on NServiceBus.Transport.Msmq version 1.0.x or below, messages can be processed even if the TTBR header has expired.

Non-native

NServiceBus also annotates outgoing messages with an NServiceBus.TimeToBeReceived header.

NServiceBus.Transport.Msmq version 1.0.x or below does not check the NServiceBus.TimeToBeReceived header.

NServiceBus.Transport.Msmq version 1.1 and above will consume a message without processing it if all of the following conditions are met:

  • The message has an NServiceBus.TimeSent header
  • The message has an NServiceBus.TimeToBeReceived header
  • The cut-off time (Time Sent + Time To Be Received) has passed
The NServiceBus.TimeSent header is based on the clock of the sending machine but the cut-off time is compared to the clock on the receiving machine. There may be issues if the sending and receiving machines have clock synchronization drift. It is not advised to use TTBR values expressed in seconds and if small TTBR durations are used to account for clock drift. If the allowed clock drift is 15 seconds and the TTBR is 30 seconds the TTBR should be set to 45 seconds.

The transport can be configured to ignore the NServiceBus.TimeToBeReceived header on incoming messages.

var transport = endpointConfiguration.UseTransport<MsmqTransport>();
transport.IgnoreIncomingTimeToBeReceivedHeaders();

Related Articles

  • Discarding Old Messages
    Automatically discard messages if they have not been processed within a given period of time.