Getting Started
Architecture
NServiceBus
Transports
Persistence
ServiceInsight
ServicePulse
ServiceControl
Monitoring
Samples

Unit Testing a custom recoverability policy

Component: NServiceBus
NuGet Package: NServiceBus (8.x)

This sample demonstrates how to test custom recoverability policies. The sample uses the policy as explained in the custom recoverability policy documentation.

Creating the policy

Any recoverability policy with NServiceBus requires a RecoverabilityConfig which contains information about immediate and delayed retries and about what happens when all retries have been exhausted. This information is configured with an EndpointConfiguration and provided by NServiceBus to the recoverability policy. This behavior can be imitated and added to a helper method:

static Func<ErrorContext, RecoverabilityAction> CreatePolicy(int maxImmediateRetries = 2, int maxDelayedRetries = 2, TimeSpan? delayedRetryDelay = null, HashSet<Type> unrecoverableExceptions = null)
{
    var failedConfig = new FailedConfig("errorQueue", unrecoverableExceptions ?? new HashSet<Type>());
    var config = new RecoverabilityConfig(new ImmediateConfig(maxImmediateRetries), new DelayedConfig(maxDelayedRetries, delayedRetryDelay.GetValueOrDefault(TimeSpan.FromSeconds(2))), failedConfig);
    return context => CustomizedRecoverabilityPolicy.MyCustomRetryPolicy(config, context);
}

Executing the policy requires an error context, which provides information about the error that occurred and how many retries have already been executed. The sample also includes a helper method that creates the error context.

static ErrorContext CreateErrorContext(int numberOfDeliveryAttempts = 1, int? retryNumber = null, Dictionary<string, string> headers = null, Exception exception = null) =>
    new ErrorContext(
        exception ?? new Exception(),
        retryNumber.HasValue
            ? new Dictionary<string, string> { { Headers.DelayedRetries, retryNumber.ToString() } }
            : headers ?? new Dictionary<string, string>(),
        "message-id",
        new ReadOnlyMemory<byte>(new byte[0]),
        new TransportTransaction(),
        numberOfDeliveryAttempts,
        "receive-address",
        new ContextBag());

Creating a test

Multiple tests can then be created using the helper methods. According to the custom recoverability policy, messages that cause a certain custom exception should be discarded and not moved to the error queue.

[Test]
public void ShouldDiscardBecauseOfCustomException()
{
    var policy = CreatePolicy();
    var errorContext = CreateErrorContext(numberOfDeliveryAttempts: 1, exception: new MyBusinessTimedOutException());

    var recoverabilityAction = policy(errorContext);

    Assert.IsInstanceOf<Discard>(recoverabilityAction, "Message should be discarded");
}

There are additional tests in the sample that show how it is possible to verify which error queue a message was sent to.

Related Articles

  • Custom Recoverability Policy
    Shows how to take full control over Recoverability by implementing a Recoverability Policy.
  • Recoverability
    Explains how exceptions are handled, and actions retried, during message processing.
  • Testing NServiceBus
    Develop service layers and long-running processes using test-driven development.

Last modified