The MSMQ transport can discard messages that exceed a configured Time-To-Be-Received (TTBR) in two ways: natively or through non-native handling by NServiceBus.
Native
When a message with a TTBR value is sent, NServiceBus maps that value to the native TimeToBeReceived
property of the MSMQ message. MSMQ continuously checks the TTBR of queued messages. Once a message has expired, it is automatically removed from the queue and the corresponding disk space is reclaimed.
MSMQ enforces a single Time-To-Be-Received value for all messages within a transaction. If multiple messages participate in the same transaction, the TTBR from the first message is applied to all. This can lead to unintended expiration and message loss.
To prevent this, TTBR is not supported by default for endpoints using transaction modes SendsAtomicWithReceive
or TransactionScope
.
The MSMQ native TTBR implementation can be disabled for messages sent as part of a transaction. In this case, messages rely on non-native TTBR handling to ensure they are discarded at receive time if the Time-To-Be-Received has expired.
Messages sent outside of a transaction will still use MSMQ's built-in native TTBR functionality.
var transport = endpointConfiguration.UseTransport<MsmqTransport>();
transport.DisableNativeTimeToBeReceivedInTransactions();
Messages sent without the native MSMQ TimeToBeReceived
property cannot be automatically removed from the queue by MSMQ. They will remain in the queue until they are read by a receiving endpoint.
If such a message is received by an endpoint running NServiceBus.Transport.Msmq version 1.0.x or earlier, the TTBR header will be ignored and the message may be processed even if it has already expired.
Non-native
In addition to using MSMQ's native behavior, NServiceBus also includes a NServiceBus.
header on outgoing messages.
NServiceBus.Transport.Msmq version 1.0.x and earlier does not evaluate the NServiceBus.
header on incoming messages.
Starting with version 1.1, the transport will discard a message without processing it if all of the following conditions are met:
- The message contains an
NServiceBus.
header.TimeSent - The message contains an
NServiceBus.
header.TimeToBeReceived - The calculated cut-off time (Time Sent + Time To Be Received) has already passed.
The NServiceBus.
header reflects the sender’s system clock, while the cut-off time is evaluated using the receiver’s system clock. If the clocks are not properly synchronized, this can lead to messages being discarded prematurely.
Avoid setting TTBR values in seconds or very short durations. If the allowed clock drift is up to 15 seconds and the TTBR is 30 seconds, the TTBR should instead be set to at least 45 seconds to prevent unintended expiration.
Learn more about clock synchronization issues.
If necessary, the transport can be configured to ignore the NServiceBus.
header on incoming messages:
var transport = endpointConfiguration.UseTransport<MsmqTransport>();
transport.IgnoreIncomingTimeToBeReceivedHeaders();