Search code examples
nservicebus

NServiceBus 6: want some errors to ignore eror queue


As per Customizing Error Handling "Throwing the exception in the catch block will forward the message to the error queue. If that's not desired, remove the throw from the catch block to indicate that the message has been successfully processed." That's not true for me even if I simply swallow any kind of exception in a behavior:

public override async Task Invoke(IInvokeHandlerContext context, Func<Task> next)
{
    try
    {
        await next().ConfigureAwait(false);
    }
    catch (Exception ex)
    {
    }
}

I put a breakpoint there and made sure execution hit the catch block. Nevertheless after intimidate and delayed retries messages inevitably ends up in error queue. And I have no more Behaviours in the pipeline besides this one.

Only if I run context.DoNotContinueDispatchingCurrentMessageToHandlers(); inside the catch block it prevents sending error to the error queue, but it also prevents any further immediate and delayed retries.

Any idea on why it works in contravention of Particular NserviceBus documentation is very appreciated

NserviceBus ver. used: 6.4.3

UPDATE:

I want only certain type of exceptions not being sent to an error queue in NServiceBus 6, however to make test case more clear and narrow down the root cause of an issue I use just type Exception. After throwing exception, execution certainly hits the empty catch block. Here is more code to that:

public class EndpointConfig : IConfigureThisEndpoint
{
    public void Customize(EndpointConfiguration endpointConfiguration)
    {

     endpointConfiguration.DefineEndpointName("testEndpoint");
     endpointConfiguration.UseSerialization<XmlSerializer>();
     endpointConfiguration.DisableFeature<AutoSubscribe>();
     configure
            .Conventions()
            .DefiningCommandsAs(t => t.IsMatched("Command"))
            .DefiningEventsAs(t => t.IsMatched("Event"))
            .DefiningMessagesAs(t => t.IsMatched("Message"));
     var transport = endpointConfiguration.UseTransport<MsmqTransport>();


     var routing = transport.Routing();
     var rountingConfigurator = container.GetInstance<IRountingConfiguration>();
     rountingConfigurator.ApplyRountingConfig(routing);
     var instanceMappingFile = routing.InstanceMappingFile();
     instanceMappingFile.FilePath("routing.xml");

     transport.Transactions(TransportTransactionMode.TransactionScope);

     endpointConfiguration.Pipeline.Register(
                    new CustomFaultMechanismBehavior(),
                    "Behavior to add custom handling logic for certain type of exceptions");

     endpointConfiguration.UseContainer<StructureMapBuilder>(c => c.ExistingContainer(container));

     var recoverability = endpointConfiguration.Recoverability();

     recoverability.Immediate(immediate => 
                {
                    immediate.NumberOfRetries(2);
                });

     endpointConfiguration.LimitMessageProcessingConcurrencyTo(16);

     recoverability.Delayed(delayed =>
        {
                    delayed.NumberOfRetries(2);
        });

     endpointConfiguration.SendFailedMessagesTo("errorQueue");
    ...
    }
}

public class CustomFaultMechanismBehavior : Behavior<IInvokeHandlerContext>
{
    public override async Task Invoke(IInvokeHandlerContext context, Func<Task> next)
    {
        try
        {
            await next().ConfigureAwait(false);
        }
        catch (Exception ex)
        {               
        }
    }
}

UPDATE 2 I think I know what's going on: message is handled by first handler that throws an exception which is caught by the Behavior catch block, but then NServiceBus runtime tries to instantiate second handler class which is also supposed to handle the message (it handles class the message is derived from). That's where another exception is thrown in a constructor of one of dependent class. StructureMap tries to instantiate the handler and all its dependent services declared in the constructor and in the process runs into the exception. And this exception is not caught by CustomFaultMechanismBehavior.

So my I rephrase my question now: Is there any way to suppress errors (ignore error queue) occurring inside constructor or simply during StructureMap classes initialization? Seems like the described way does not cover this kind of situations


Solution

  • Your behavior is activated on Handler invocation. This means you are catching exceptions happening inside the Handle method so any other exception, e.g. in the Constructor of the handler would not be caught.

    To change the way you 'capture' the exceptions, you can change the way the behavior is activated, e.g. change it from Behavior<IInvokeHandlerContext> to Behavior<ITransportReceiveContext> which is activated when the transport receives a message. You can investigate on different stages and behaviors to see which one suits your purpose best.