I have an endpoint which receives messages and creates a saga in order to be able to response to that corresponding message at a later point in time. The message contains some xml document and this xml doc will be validated within this message handler. If we catch some validation errors, we create a message response (no saga involved) to inform the originating endpoint that something with the xml doc was wrong. In the case of a validation error, the saga is not stored as expected and as required. But I still want to reply to the originating endpoint. The problem is, that nservicebus also does a rollback on the reply.
Is there a way to go? I tried to wrap the reply into a new transaction scope, but this did not work:
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
this.bus.Reply(message);
scope.Complete();
}
Any advice? Thanks in advance
Additional Information:
The orginal problem was that I did not throw (or rethrow) any exception but replying
to the originator in the catch section (I know its bad design).
The Saga is stored with a unique attribute applied on a id, which comes from the originating endpoint. And since I did not throw or pass any exception in the reply case (validation error occured), nservicebus always stored the saga. If the originating endpoint corrects the xml so that this is valid and resends a message (with the same id) nservicebus tries to store a new saga with the same id (causes concurrency exception on ravenDB because the saga with that unique property already exists). As a quick fix, I want to change the unique property and use instead the message id as the unique prop. In that case, I am sure that the message id is always unique and a saga concurrency exception could not happen again. Do you know if that causes any side effects?
You may be able to leverage the message handler pipeline. The first handler in your pipeline could do the validation and any response if necessary. During the validation, do not throw an exception, just reply. The second handler could initiate the Saga and set the state to be "Invalid" or something like that. My assumption is that you will get another request with valid data and then you will follow the "normal" process and set the state to "Valid" and continue on.
Related
I'm making a call to a WCF service that will initiate a batch of credit card charges. If an exception occurs, I want to know whether it occurred prior to the method executing and cards actually being charged. For example, with a TimeoutException, there's no way to know whether the WCF method executed so I need to make sure those charges aren't retried until the situation is investigated. But if the network was just down, or the server cert expired, or anything else happened prior to the method actually executing, I can un-lock my records to be retried later without human intervention.
try
{
var response = wcfClient.ProcessBatch(paymentBatch);
wcfClient.Close();
//...
}
catch(CommunicationException)
{
//Safe to assume ProcessBatch did not execute?
wcfClient.Abort();
}
catch(TimeoutException)
{
//Indeterminate state. Have to assume operation may have succeeded server-side
wcfClient.Abort();
}
catch(Exception)
{
//Assuming operation may have succeeded server-side
}
This is using a wsHttpBinding. Does a CommunicationException guarantee the method did not execute or could it also be thrown during the response?
According to the CommunicationException documentation on MSDN, a CommunicationException Exceptioon is a superclass of errors that fall into two subcategories, both related to to errors in the SOAP datagram.
Conversely, a TimeoutException is pretty straightforward: "The exception that is thrown when the time allotted for a process or operation has expired." The allotted time is probably set by the owner of the service, and you may or may not have a mechanism by which to override it.
For future reference, two quick Bing searches returned both of the articles cited herein.
I want to be able to retry a failed NServicebus message but with an updated body.
I have successfulle updated the body tag in ravendb (the servicecontrol instance) of a "FailedMessages" Document
but
the api still returns the old body (from the bodyUrl). So when i retry the message from our custom document viewer the body is still the old when reaches the Handler.
Is it possible to update the body?
-EDIT-
When you do a retry using the Servicecontrol API. Is it the message that is in the error queue that is resent or is it data collected from the servicecontrol ravendb instance that are put together and sent?
It is not possible to update the body of a message, it goes against the basic principle of messages are immutable...
If there is a business reason to modify the data then it should be done by your application logic i.e. a reconciliation process.
Make sense?
EDIT:-
Error messages are processed from the error queue and stored in a RavenDB document, when a retry or a retry batch is invoked the message is composed and sent to the original endpoint that was processing the field message. Just to be clear.
Please note: ServiceControl's API is not a public and supported API...
I just managed to update the body of a message. It is possible after all.
Here is some sourcecode from ServiceControl:
DocumentStore.DatabaseCommands.PutAttachment("messagebodies/" + bodyId, null, bodyStream, new RavenJObject
{
{"ContentType", contentType},
{"ContentLength", bodySize}
});
Previously I tried to update the FailedMessage document which has a body tag. But I needed to update the Attachment. The bodyId in the above code is not the UniqueMessageId but MessageId found in ProcessingAttempts -> MessageMetadata -> MessageId.
I have an interesting use case where certain exception types mean "This message is no longer valid and should be ignored" but this code doesn't have any awareness of the Bus in order to call Bus.DoNotContinueDispatchingCurrentMessageToHandlers().
I loathe boilerplate code like try/catch blocks that need to be present in every single message handler. So I started implementing a UnitOfWork to handle and swallow the exception, but I can't find a way to tell the framework that "Yes, this code generated an exception, but forget about that and just complete the transaction."
Bus.DoNotContinueDispatchingCurrentMessageToHandlers() does not work. I tried having an ITransport injected and calling AbortHandlingCurrentMessage() but that caused the entire universe to blow up. Even stepping through the source code I seem to be at a loss.
Note that it very well may be that this is a horrible idea, because faking that there is no exception when there is in fact an exceptional case would cause the transaction to commit, causing who knows how many bad unknown side effects. So it would be preferable to have a method that still rolls back the transaction but discards the message. But I would be interested in a potential "Yes I know what I'm doing, commit the transaction regardless of the exception" option as well.
As of NServiceBus version 4.4 you can control this by injecting a behavior into our handler pipeline.
This let's you control which exceptions to mute.
class MyExceptionFilteringBehavior : IBehavior<HandlerInvocationContext>
{
public void Invoke(HandlerInvocationContext context, Action next)
{
try
{
//invoke the handler/rest of the pipeline
next();
}
//catch specific exceptions or
catch (Exception ex)
{
//modify this to your liking
if (ex.Message == "Lets filter on this text")
return;
throw;
}
}
There are several samples of how this works:
http://docs.particular.net/samples/pipeline/
That said I totally agree with Ramon that this trick should only be used if you can't change to design to avoid this.
A dirty solution would be having a unit of work test the exception, put the message id in a shared 'ignore' bag (concurrent dictionary in memory, db, what works for you) , let it fail so that everything is rolled back, in the retry have a generic message handler compare the message ID and let that call Bus.DoNotContinueDispatchingCurrentMessageToHandlers()
If you do not want to work with a unit of work then you could try to use the AppDomain.FirstChanceException.
I wouldn't advice any of these as good solution :-)
Why would you like to 'swallow' unhandled exceptions?
If you want to ignore an exception then you should catch these in the handler and then just return and log this.
What I'm more interested in is what about state? You maybe have already writen to a store. Shouldn't these writes be rolled back? If you swallow an exception the transaction commits.
It seems to me you are running in a kind of 'at least once delivery' environment. THen you need to store some kind of message id somewhere.
Or is it an action initiated by several actors based on a stale state? In that case you need to have first/last write wins construction that just ignores a command based on a stale item.
If you handl an event then swallowing a exception seems not correct. They usually say that you can ignore commands but that you always have to handle events.
Shouldn't this be part of validation? If you validate a command then you can decide to ignore it.
How can I access the current context from within a message mutator?
I also need to have access to the saga data.
I want to pass certain data transparently from both the sender and implementers (handlers). This data will be set in the outgoing headers. Depending on the situation, if the handler is of type Saga, I want to set some of these properties into the saga data.
Later when a call "ReplyToOriginator" is detected, I want to grab the values from saga and set it back into the headers of the reply message.
So how can I do this from within the message mutator?
All the examples I have seen so far seems to indicate that it has access only to the message and not context.
I have a generic service with this interface
[OeprationContract(Action="*", ReplyAction="*")]
Message ProcessMessage(Message message);
In the implementation, I have to set up the headers of the reply message.
Is there a way to create the right addressing headers from the input message or do I have to set everything manually (i.e. copy In.replyTo to out.To, copy In.messageId to out.MessageId, ...)
Thanks
You'll need to do it manually; when you declare an operation taking an returning a Message object you're basically telling WCF that you want total control over the message, so no correlation between request and reply will be done for you.