NServiceBus 6: want some errors to ignore eror queue - nservicebus

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

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.

Related

Should we handle dataAccessException and jdbc exception in springboot in production?

public UserMailDto getUserByEmail(String email) throws UserExceptionMessage {
try {
return userRepository.searchByMail(email);
} catch (DataAccessException | JDBCConnectionException accessException) {
com.example.user_service.config.log.Logger.errorLog("UserService", accessException.getMessage());
throw new DataAccessExceptionMessage(Messages.ERROR_TRY_AGAIN + accessException.getMessage());
}
}
In my view you should handle it, but not with a try..catch block in what seems to be your service. Why are you catching the Exception and then rethrowing you own custom Exception with a message? You will need to handle that Exception at some point in your code to. So you are not really handling it here.
It looks like you are building a web app, so I would recommend that you handle your Exceptions in one central place in a #ControllerAdvice class. You can read about it here. This way you can really handle the Exception, by returning a corresponding status code to the user. 503 in your case.

How can my WCF service recover from unavailable message queue?

I have a WCF service that receives messages from the Microsoft Message Queue (netMsmqBinding).
I want my service to recover if the message queue is unavailable. My code should fail to open the service, but then try again after a delay.
I have code to recognize the error when the queue is unavailable:
static bool ExceptionIsBecauseMsmqNotStarted(TypeInitializationException ex)
{
MsmqException msmqException = ex.InnerException as MsmqException;
return ((msmqException != null) && msmqException.HResult == (unchecked((int)(0xc00e000b))));
}
So this should be straightforward: I call ServiceHost.Open(), catch this exception, wait for a second or two, then repeat until my Open call is successful.
The problem is, if this exception gets thrown once, it continues to be thrown. The message queue might have become available, but my running process is in a bad state and I continue to get the TypeInitializationException until I shut down my process and restart it.
Is there a way around this problem? Can I make WCF forgive the queue and genuinely try to listen to it again?
Here is my service opening code:
public async void Start()
{
try
{
_log.Debug("Starting the data warehouse service");
while(!_cancellationTokenSource.IsCancellationRequested)
{
try
{
_serviceHost = new ServiceHost(_dataWarehouseWriter);
_serviceHost.Open();
return;
}
catch (TypeInitializationException ex)
{
_serviceHost.Abort();
if(!ExceptionIsBecauseMsmqNotStarted(ex))
{
throw;
}
}
await Task.Delay(1000, _cancellationTokenSource.Token);
}
}
catch (Exception ex)
{
_log.Error("Failed to start the service host", ex);
}
}
And here is the stack information. The first time it is thrown the stack trace of the inner exception is:
at System.ServiceModel.Channels.MsmqQueue.GetMsmqInformation(Version& version, Boolean& activeDirectoryEnabled)
at System.ServiceModel.Channels.Msmq..cctor()
And the top entries of the outer exception stack:
at System.ServiceModel.Channels.MsmqChannelListenerBase`1.get_TransportManagerTable()
at System.ServiceModel.Channels.TransportManagerContainer..ctor(TransportChannelListener listener)
Microsoft have made the source code to WCF visible, so now we can work out exactly what's going on.
The bad news: WCF is implemented in such a way that if the initial call to ServiceModel.Start() triggers a queueing error there is no way to recover.
The WCF framework includes an internal class called MsmqQueue. This class has a static constructor. The static constructor invokes GetMsmqInformation, which can throw an exception.
Reading the C# Programming Guide on static constructors:
If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.
There is a programming lesson here: Don't put exception throwing code in a static constructor!
The obvious solution lies outside of the code. When I create my hosting service, I could add a service dependency on the message queue service. However, I would rather fix this problem with code then configuration.
Another solution is to manually check that the queue is available using non-WCF code.
The method System.Messaging.MessageQueue.Exists returns false if the message queue service is unavailable. Knowing this, the following works:
private const string KNOWN_QUEUE_PATH = #".\Private$\datawarehouse";
private static string GetMessageQueuePath()
{
// We can improve this by extracting the queue path from the configuration file
return KNOWN_QUEUE_PATH;
}
public async void Start()
{
try
{
_log.Debug("Starting the data warehouse service");
string queuePath = GetMessageQueuePath();
while(!_cancellationTokenSource.IsCancellationRequested)
{
if (!(System.Messaging.MessageQueue.Exists(queuePath)))
{
_log.Warn($"Unable to find the queue {queuePath}. Will try again shortly");
await Task.Delay(60000, _cancellationTokenSource.Token);
}
else
{
_serviceHost = new ServiceHost(_dataWarehouseWriter);
_serviceHost.Open();
return;
}
}
}
catch(System.OperationCanceledException)
{
_log.Debug("The service start operation was cancelled");
}
catch (Exception ex)
{
_log.Error("Failed to start the service host", ex);
}
}

NServiceBus Send() vs SendLocal() and exceptions

We are implementing a saga that calls out to other services with NServiceBus. I'm not quite clear about how NServiceBus deals with exceptions inside a saga.
Inside the saga we have a handler, and that handler calls an external service that should only be called once the original message handler completes succesfully. Is it okay to do:
public void Handle(IFooMessage message)
{
var message = Bus.CreateInstance<ExternalService.IBarMessage>();
Bus.Send(message);
// something bad happens here, exception is thrown
}
or will the message be sent to ExternalService multiple times? Someone here has suggested changing it to:
// handler in the saga
public void Handle(IFooMessage message)
{
// Do something
var message = Bus.CreateInstance<ISendBarMessage>();
Bus.SendLocal(message);
// something bad happens, exception is thrown
}
// a service-level handler
public void Handle(ISendBarMessage message)
{
var message = Bus.CreateInstance<ExternalService.IBarMessage>();
Bus.Send(message);
}
I've done an experiment and from what I can tell the first method seems fine, but I can't find any documentation other than http://docs.particular.net/nservicebus/errors/ which says:
When an exception bubbles through to the NServiceBus infrastructure, it rolls back the transaction on a transactional endpoint, causing the message to be returned to the queue, and any messages that user code tried to send or publish to be undone as well.
Any help to clarify this point would be much appreciated.
As long as you're doing messaging from your saga and not doing any web service calls, then you're safe - no need to do SendLocal.

What WCF Exceptions should I retry on failure for? (such as the bogus 'xxx host did not receive a reply within 00:01:00')

I have a WCF client that has thrown this common error, just to be resolved with retrying the HTTP call to the server. For what it's worth this exception was not generated within 1 minute. It was generated in 3 seconds.
The request operation sent to xxxxxx
did not receive a reply within the
configured timeout (00:01:00). The
time allotted to this operation may
have been a portion of a longer
timeout. This may be because the
service is still processing the
operation or because the service was
unable to send a reply message. Please
consider increasing the operation
timeout (by casting the channel/proxy
to IContextChannel and setting the
OperationTimeout property) and ensure
that the service is able to connect to
the client
How are professionals handling these common WCF errors? What other bogus errors should I handle.
For example, I'm considering timing the WCF call and if that above (bogus) error is thrown in under 55 seconds, I retry the entire operation (using a while() loop). I believe I have to reset the entire channel, but I'm hoping you guys will tell me what's right to do.
What other
I make all of my WCF calls from a custom "using" statement which handles exceptions and potential retires. My code optionally allows me to pass a policy object to the statement so I can easily change the behavior, like if I don't want to retry on error.
The gist of the code is as follows:
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ProxyUsing<T>(ClientBase<T> proxy, Action action)
where T : class
{
try
{
proxy.Open();
using(OperationContextScope context = new OperationContextScope(proxy.InnerChannel))
{
//Add some headers here, or whatever you want
action();
}
}
catch(FaultException fe)
{
//Handle stuff here
}
finally
{
try
{
if(proxy != null
&& proxy.State != CommunicationState.Faulted)
{
proxy.Close();
}
else
{
proxy.Abort();
}
}
catch
{
if(proxy != null)
{
proxy.Abort();
}
}
}
}
You can then use the call like follows:
ProxyUsing<IMyService>(myService = GetServiceInstance(), () =>
{
myService.SomeMethod(...);
});
The NoInlining call probably isn't important for you. I need it because I have some custom logging code that logs the call stack after an exception, so it's important to preserve that method hierarchy in that case.

Throwing FaultException<T> from worker thread crashes WCF

What I found out was if you throw a FaultException from a new worker thread, it doesnt percolate up to the client but just crashes WCF.
Any solutions???
example:
var thread = new Thread(new ThreadStart(
delegate
{
new Killbot().KillAllHumans(); // Throws a FaultException
}));
The simplest way would be to wrap the call in a try-catch block and log the exception:
var thread = new Thread(new ThreadStart(
delegate
{
try
{
new Killbot().KillAllHumans(); // Throws a FaultException
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.ToString());
}
}));
If you want to handle the exception in your main thread you would have to use BeginInvoke and EndInvoke in combination with an AsyncCallback.
Personally I would not bother with background threads in a WCF service. A service is effectively a "background worker" anyway. All you need to do is ensure that any blocking calls you make inside the service don't affect other clients. You can do this by changing the concurrency mode:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
class MyServiceClass : IMyServiceContract {
public void KillAll() {
new Killbot().KillAllHumans(); // Throws a FaultException
}
}
When that is set, WCF will call your service methods on multiple threads with no attempt to synchronise them. As long as you write your code with this in mind, you can do all the blocking calls you want.