What's the proper way to handle concurrency exceptions in EventStore? - nservicebus

Using JOliver EventStore 3.0 and reciving commands from NServiceBus, what's the proper way to handle concurrency exceptions? If I have more than one worker thread, this could be a common occurance.
Option 1
try
{
// store the event
...
}
catch (ConcurrencyException)
{
_bus.HandleCurrentMessageLater();
}
Option 2
Let it throw back to NServiceBus and get retried with the MsMqTransportConfig.MaxRetries option from the config.
Option 3
Something I'm not thinking of?

You could compare the uncommitted events with the committed events and see if they actually conflict (according to your business rules) - if there's no conflicts then you can allow the events to be persisted, otherwise re-throw.
Generally though I just let it throw and have NServiceBus retry.

Related

NServicesBus disable FLR for specific exceptions completely

I'm trying to disable retries for some specific exceptions completely.
I know that in my code - when I'm trying to handle message X and if the handler throw a "ZZZ" type exception, I'm sure there's no way any number of retries would help;
What I want to do is send that message directly to error queue immediately without any retries.
How can i do that ?
I know you've already accepted an answer, but since you are trying to circumvent the plumbing builtin for a very specific scenario, you could handle the message in a try/catch and either send the message directly to the error queue or let the FLR/SLR handle it.
Please note, this is not an ideal scenario. In most cases, it is actively discouraged to handle the error handling of messages and instead allow the infrastructure to manage it.
Here's a possible implementation:
public void Handle(SomeCommand message)
{
try
{
//Do thing that might throw exception
}
catch (SpecificException ex)
{
_bus.Send(new Address("errorQueue", "machine"), message);
}
catch (Exception ex)
{
throw ex;
}
}
EDIT I'm promoting Marcin's comment to be included in this answer so it isn't missed:
Please bear in mind that by using this approach without setting
appropriate message headers you will lose the ability to return these
failed messages to the source queue. Please take a look at this doco
for details: http://docs.particular.net/nservicebus/messaging/headers#retries-handling-headers. – Marcin
Hoppe
You can't for the first level retries, only for the second level retries. I personally wouldn't worry about it (I have something similar, where certain exceptions I know that it won't be fixed). There's generally no downside to letting them go in the FLR.

What approach is there for handling and returning errors (non-exceptional and exceptional) in Domain Driven Design entities and aggregate roots?

I'm trying to find a good article/examples of how DDD entities treat errors (and what would be considered exceptional errors and what wouldn't) and how they pass them up to the calling application layer (which usually wraps operations in a transaction that would need to be rolled back).
Currently I'm thinking to consider all errors that would break the transaction of an aggregate (such as validation) to be exceptions. This way I can rollback the transaction in a "catch" block. For example:
SomeApplicationService:
// start transaction here
// ...
try
{
$user = $userRepository->userOfId($id);
$user->doSomething();
$user->doSomethingElse(); // <-- imagine an error thrown here
$userRepository->save($user);
}
catch (CustomFriendlyForUIException $e)
{
// Custom Friendly for UI error
// Rollback transaction and add error/message to UI payload DTO
// ...
}
catch (AnotherCustomException $e)
{
// Not friendly to UI, so use general error message for UI
// Rollback transaction and add error/message to UI payload DTO
// ...
}
catch (Exception $e)
{
// Catch all other exceptions, use general error message for UI
// Rollback transaction and add error/message to UI payload DTO
// ...
}
// end transaction
Is this the correct approach, or am I missing something?
Usually, there are two types of error:
business errors that have a business meaning. For instance, StockFullError, ProductNotAvailableError, etc. These errors are expected because they are explicitly created in the code.
These kind of error can be implemented using exceptions or using the
functional way: explicitly show errors in the return type. For
instance: Either<Error, T>.
Exception make the code simpler. Handling error the functional programming way make the code easier to reason about and more predictable. I would advise the latter.
infrastructure errors are errors linked to the database, network, external services, etc. These error are usually unexpected.
Error happen. And when error happen, you don't want the application to be in an inconsistent state. For instance, you want to avoid to have half of the aggregate stored in the datastore.
Aggregate integrity
The key problem here is to maintain the aggregate integrity. The critical point is when the aggregate has to be written in the datastore. I can see two situations:
The operation to persist the aggregate is atomic
As soon as your datastore can provide atomic operations, there is no worry to have about the data integrity because the result of an atomic operation is either a failure or a success. There is no partial writes.
That means that you can just let your http layer handle exception and return 500 for instance.
The operation to persist the aggregate is not atomic
Sometimes, ensuring atomicity is not possible.
One aggregate in several tables
If you need to store your aggregate in several tables, there are some solutions:
Transactions. Surrounding the code in a transaction could be a solution. However transactions have some disadvantages. If the computation is too long or if this part of the code is called too often, it would slow down the application.
Unit Of Work is an old pattern. The idea is to register operations that you want to do: add, update, delete, etc. Eventually, UOW applies the changes to the database using a transaction. See Fowler's article for more information.
SAGAs: sometimes a big transaction is not possible
When you send an email and save something in the database, you can't include the email in the transaction.
In that case, you can use SAGAs. The idea is that, sometime, you can't have one single big transaction to enforce atomicity. However, it is usually easy to have several small transactions.
The idea of a SAGA is to associate every single transaction to a compensating transaction. For instance given the "transaction": send an email to confirm that the product is bought, the compensating "transaction" could be sent an email to apologise with a coupon.
Every transaction small transaction is run. If one of these fails, compensating transaction are run. Eventually, this enables to get atomicity.

Difference between FireAndForget and Async behavior for publishing

Currently, we are using StackExchange.Redis and, as it does not provides "blocking pops", we are doing as suggested on the documentation:
db.ListLeftPush(key, newWork, flags: CommandFlags.FireAndForget);
sub.Publish(channel, "");
What is the difference from this to the following?
db.ListLeftPushAsync(key, newWork);
sub.Publish(channel, "");
We know the purpose of the commands, what we would like to know is if it has any difference internally or any risk of behaving differently? (Execution order etc.)
There's a main difference comparing fire and forget vs calling an async operation and not awaiting it.
Fire and forget means that not only you're not waiting for the result but you don't care if it works or not, while an async operation may throw an exception once it has ended if something goes wrong.
In the other hand, when you issue a fire and forget command, StackExchange.Redis doesn't try to retrieve the command result internally, which is better if you just want the so-called fire and forget behavior when issuing commands.
You may check this difference if you open ConnectionMultiplexer source code and you see how ExecuteAsyncImpl / ExecuteSyncImpl methods are implemented:
// For example, ExecuteAsyncImpl...
if (message.IsFireAndForget)
{
TryPushMessageToBridge(message, processor, null, ref server);
return CompletedTask<T>.Default(null); // F+F explicitly does not get async-state
}
else
{
var tcs = TaskSource.CreateDenyExecSync<T>(state);
var source = ResultBox<T>.Get(tcs);
if (!TryPushMessageToBridge(message, processor, source, ref server))
{
ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, message.Command, message, server));
}
return tcs.Task;
}
Answer to some OP comment
Hi. Thanks for your answer. We know the purpose of the commands, what
we would like to know is if it has any differrence internally or any
risk of behaving differently (execution order etc.)
Since the async operation won't be finished when you publish the message on the Redis channel, it can happen that you publish the message and the operation gets executed never. You lose a lot of control.
When you send a fire and forget command, it mightn't be executed too, but you know that the try was done before you publish the channel's message. Therefore, you shouldn't use async operations to implement fire and forget pattern when using StackExchange.Redis.
You may check this other related Q&A: Stackexchange.redis does fire and forget guarantees delivery?

NServiceBus UnitOfWork to swallow certain exceptions and avoid message failure

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.

Why configure with Sagas()?

Why is it necessary to configure with Sagas()? I ask because I had been running a saga with raven persistence for the last few months before I noticed the Sagas() is not in the configure.with, in fact I realized I was missing a bit of the RavenPersistence stuff as well. Yet, as far as I know Sagas have been working 98% of the time and persisting to Raven. So I wonder what the Sagas() configuration does differently than not configuring it.
The reason I say 98% of the time is I do notice random messages falling out of a method and not sending the next message it is designated to send in the Saga. I am curious if not having the proper configuration is the cause of this.
_logger.InfoFormat("1.1 - Preparing Saga for; File: {0}", message.FileNumber);
//Creates Saga information
SetupSaga(uploads,
message.Documents,
message.ProcedureID.GetValueOrDefault(0),
file.Client.Id,
message.FileNumber,
message.Stage,
user);
_logger.InfoFormat("1.2 - Upload Saga Unique ID; File: {0}, UniqueID: {1}", message.FileNumber, Data.UniqueID);
Bus.SendLocal(new GetLoanInformation {
UniqueID = Data.UniqueID
});
The NServiceBus Host does a lot of configuration automatically based on roles and profiles. Both the Sagas configuration and the Raven persistence are handled for you automatically. You would only need to do this manually if you were going to run a Saga when self-hosting, which would be somewhat rare.
For a better idea of what happens as a result of all the different roles and profiles, check out All About NServiceBus Host Profiles and Roles. (Disclaimer: This is my blog post.)
The problem you're mentioning is due to something else, but a lot more information would be required to diagnose it.