NServiceBus Send() vs SendLocal() and exceptions - nservicebus

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.

Related

Is there a global exception handler for NServiceBus?

The current advice on handling exceptions in NServiceBus is to use the built in facilities. Errored out messages go to the error message queue, and a log is written to disk.
But what if I want to send my errors to a service like AirBrake which has better functionality for grouping similar exceptions, metrics, and other good stuff? Is there a global exception handler I can tap into?
As mentioned in the original post the recommended solution is to use ServicePulse for monitoring errors. The client I currently work for is using a custom made centralized logger, and we want NServiceBus to log to this log store when messages are forwarded to the error queue.
We could have achieved this by just editing the log4net config if the exception from NServiceBus had included the original exception, currently NServiceBus just logs a generic error message with no details about what caused the failure.
NServiceBus has a class named NServiceBus.Faults.ErrorsNotifications which contains the following observables:
MessageSentToErrorQueue
MessageHasFailedAFirstLevelRetryAttempt
MessageHasBeenSentToSecondLevelRetries
You can subscribe to these observables when the endpoint starts, like in the following example which logs an error when messages are sent to the error queue:
public class GlobalErrorHandler : IWantToRunWhenBusStartsAndStops
{
private readonly ILogger _logger;
private readonly BusNotifications _busNotifications;
readonly List<IDisposable> _notificationSubscriptions = new List<IDisposable>();
public GlobalErrorHandler(ILogger logger, BusNotifications busNotifications)
{
_logger = logger;
_busNotifications = busNotifications;
}
public void Start()
{
_notificationSubscriptions.Add(_busNotifications.Errors.MessageSentToErrorQueue.Subscribe(LogWhenMessageSentToErrorQueue));
}
public void Stop()
{
foreach (var subscription in _notificationSubscriptions)
{
subscription.Dispose();
}
}
private void LogWhenMessageSentToErrorQueue(FailedMessage message)
{
var properties = new
{
MessageType = message.Headers["NServiceBus.EnclosedMessageTypes"],
MessageId = message.Headers["NServiceBus.MessageId"],
OriginatingMachine = message.Headers["NServiceBus.OriginatingMachine"],
OriginatingEndpoint = message.Headers["NServiceBus.OriginatingEndpoint"],
ExceptionType = message.Headers["NServiceBus.ExceptionInfo.ExceptionType"],
ExceptionMessage = message.Headers["NServiceBus.ExceptionInfo.Message"],
ExceptionSource = message.Headers["NServiceBus.ExceptionInfo.Source"],
TimeSent = message.Headers["NServiceBus.TimeSent"]
};
_logger.Error("Message sent to error queue. " + properties, message.Exception);
}
}
The observable is implemented by using Reactive Extensions, so you will have to install the NuGet package Rx-Core for this to work.
Could you maybe use a custom log4net configuration to do it?
http://help.airbrake.io/discussions/suggestions/157-net-plug-in-for-api-v2
There is an interface in NServiceBus called IManageMessageFailures, but I don't believe you can use it in conjucntion with the Second Level Retries so you would probably lose that if you did go for your own.
You could write the errors to SQL Server with log4net and the from there you could forward them to AirBrake using their API marking each error in the error table as sent afterwards maybe?
We switched to Serilog, it has perfect logging ans tracing support for NServiceBus. Creating a custom Serilog sink that will send your log events wherever you want is quite easy.
I would suggest that you create a custom endpoint that feeds off the error queue and uploads the data to AirBrake.
Side note: v4.0|4.1 will come with a nice Rest-Api that gives you nice management/querying capabilities for the errors. Tools like the Profiler and Ops will use this api to present the data to you in various ways.
http://particular.net/service-platform

NServiceBus HandleMessage async causes crash

I'm looking at NServiceBus v3.3.0.0, in our MessageHandler it calls an external WCF service.
If the WCF service is called synchronously and that service throws an exception, NServiceBus handles it perfectly and retries the process as per configuration.
But, if the WCF service is called asynchronously and an exception is thrown then the subscriber process crashes.
So, for example, this handles the exception fine if service.Update throws
public class LeagueMessageHandler : IHandleMessages<LeagueMessage>
{
public void Handle(LeagueMessage message)
{
var service = new LeagueService.LeagueContractClient();
var league = service.Update(leagueDto);
}
}
but if the call to service.UpdateAsync throws an exception then the process crashes
public class LeagueMessageHandler : IHandleMessages<LeagueMessage>
{
public async void Handle(LeagueMessage message)
{
var service = new LeagueService.LeagueContractClient();
var league = await service.UpdateAsync(leagueDto);
}
}
The WCF service is just added as a Service Reference to the class library, it generates the Async method wrappers.
Edit after Adam and Udi comments.
It looks like the issue is unrelated to NServiceBus it's more to do with how console applications handle async methods throwing exceptions. Please see thread
Catch unhandled exceptions from async
Stephen Cleary has written this
http://nuget.org/packages/Nito.AsyncEx
which helps you roll your own SynchronisationContext which handles catching the exception. So the WCF call above is wrapped such...
var league = AsyncContext.Run(() => service.UpdateAsync(leagueDto));
when the exception gets thrown it is caught within that context and the console app no longer closes.
When you call it async, the exception happens on a different thread than the one that is processing the message. For that reason, there's no way for NServiceBus to know which message was the one to cause that exception, so it can't roll anything back.
When using NServiceBus, your overall architecture is already asynchronous - there really isn't any need to perform these WCF calls asynchronously.

synchronous send/reply in generic host

I am trying to use synchronous send/reply from the handler function of the generic host windows service as below. But I think NServiceBus will send the message only after completing the handle function(during the current transaction complete). So below code will hang in ‘synchronousHandle.AsyncWaitHandle.WaitOne()’.
What should be the best approach here? Could you please guide me…
Handler constructer
ConstructorFunction(bus)
{
Bus = bus
}
code in the handle function.
// sent the message to the bus and wait for the reply
IMessage response = null;
var synchronousHandle = Bus.Send(service2queue, requestMessage)
.Register(
(AsyncCallback)delegate(IAsyncResult asyncResult)
{
// Callback block for reply message
// Reply message received
NServiceBus.CompletionResult completionResult = asyncResult.AsyncState as NServiceBus.CompletionResult;
if (completionResult != null && completionResult.Messages.Length > 0)
{
// Always expecting one IMessage as reply
response = completionResult.Messages[0];
}
},
null);
// block the current thread till the reply received.
synchronousHandle.AsyncWaitHandle.WaitOne();
Thanks,
Ajai
nservicebus tries to make things as hard as possible when they shouldn't be done.
from the nservicebus documentation:
Bus.Send(request).Register(asyncCallback, state)
Callback only fires on first response, then is cleaned up to prevent memory leaks.
Doesn’t survive restarts – not suitable for server-side
assuming that you are on a server side (am guessing here because you showed us a messagehandler) i would considering a redesign.
service1 gets a notification about messageA
service1 sends message requestMessage to service2
service2 replies with message responseMessage to service1
service1 handles responseMessage and continues processing
if you want to wait for multiple messages in service1 before continuing the processing try considering to implement sagas.

WCF nested Callback

The backgound: I am trying to forward the server-side ApplyChangeFailed event that is fired by a Sync Services for ADO 1.0 DBServerSyncProvider to the client. All the code examples for Sync Services conflict resolution do not use WCF, and when the client connects to the server database directly, this problem does not exist. My DBServerSyncProvider is wrapped by a head-less WCF service, however, and I cannot show the user a dialog with the offending data for review.
So, the obvious solution seemed to be to convert the HTTP WCF service that Sync Services generated to TCP, make it a duplex connection, and define a callback handler on the client that receives the SyncConflict object and sets the Action property of the event.
When I did that, I got a runtime error (before the callback was attempted):
System.InvalidOperationException: This operation would deadlock because the
reply cannot be received until the current Message completes processing. If
you want to allow out-of-order message processing, specify ConcurrencyMode of
Reentrant or Multiple on CallbackBehaviorAttribute.
So I did what the message suggested and decorated both the service and the callback behavior with the Multiple attribute. Then the runtime error went away, but the call results in a "deadlock" and never returns. What do I do to get around this? Is it not possible to have a WCF service that calls back the client before the original service call returns?
Edit: I think this could be the explanation of the issue, but I am still not sure what the correct solution should be.
After updating the ConcurrencyMode have you tried firing the callback in a seperate thread?
This answer to another question has some example code that starts another thread and passes through the callback, you might be able to modify that design for your purpose?
By starting the sync agent in a separate thread on the client, the callback works just fine:
private int kickOffSyncInSeparateThread()
{
SyncRunner syncRunner = new SyncRunner();
Thread syncThread = new Thread(
new ThreadStart(syncRunner.RunSyncInThread));
try
{
syncThread.Start();
}
catch (ThreadStateException ex)
{
Console.WriteLine(ex);
return 1;
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine(ex);
return 2;
}
return 0;
}
And this is my SyncRunner:
class SyncRunner
{
public void RunSyncInThread()
{
MysyncAgent = new MySyncAgent();
syncAgent.addUserIdParameter("56623239-d855-de11-8e97-0016cfe25fa3");
Microsoft.Synchronization.Data.SyncStatistics syncStats =
syncAgent.Synchronize();
}
}

Is there a way to get error feedback on asynchronous WCF calls?

I have a WCF service which works 100% in the synchronous (blocking) mode and I now need to rework a call so that it uses the async pattern.
The service uses authentication and performs a chunked file transfer from client to server so I have reworked it to use the 'Begin' async prefix to kick off the call.
Now I'm testing for errors by deliberately mangling the user credentials which causes the call to timeout on each part of the file chunk it tries to transfer, which takes ages. The problem is that I don't get any error feedback and can't see how to get any if the async call fails. This leads to some very large files failing to upload at all, but the client being unaware of it as no exceptions are thrown.
I have the Debug->Exceptions->All CLR exceptions ticked to see if there are any exceptions being swallowed but still nothing.
So in summary, how do you get error feedback from async calls in WCF?
Thanks in advance,
Ryan
The server caches the exception for you and if you call the end operation completion method for your async call it will throw any exceptions that occured.
private void go_Click(object sender, EventArgs e)
{
client.BeginDoMyStuff(myValue, new AsyncCallback(OnEndDoMyStuff), null);
}
public void OnEndDoMyStuff(IAsyncResult asyncResult)
{
this.Invoke(new MethodInvoker(delegate() {
// This will throw if we have had an error
client.EndDoMyStuff(asyncResult);
}));
}