Is it possible to have conditional flow in the NServiceBus Saga? - nservicebus

I am new to NServiceBus & its Saga... is it possible to implement conditional flow in the sagas?
saga:
s->a->b->e
At 'a', i should be able make a choice whether to go b or new state c.
From 'c' again i should reach e

Short answer yes.
Saga is a coordinator of the process flow. Based on the state, send a message of one or another type that is handled by the saga to get to one or another state.

Related

update publisher order status after receiving event via pub sub pattern

I have an order service that publishes an order status changed event to multiple services with rabbitmq (masstransit).
These subscribers are smart enough to know if they can handle the order or not(the name of the service is in the event).
I use the pub sub pattern instead of the command pattern so that i can add new subscribers as the application grows without needing to change the business logic in the publisher.
The problem is that i would like to send an update back to the publisher after one of the subscribers has accepted the order or finished it.
I suspect there are two ways for handling this
send command to the publisher to update the order status
publish event
My questions is which one is de preferred way of doing this?
And if it is the second option then where should this event live(in the publisher.contracts library)? or should the publisher.contracts only have events that it publishes itself.
I typically would go with the second option since it gives flexibility but it's probably more so a business requirement so it depends. On where the contract will live, since it's a multiple service probably best to create a separate library for your contract. This way you don't reference the entire project.

How to make a Saga handler Reentrant

I have a task that can be started by the user, that could take hours to run, and where there's a reasonable chance that the user will start the task multiple times during a run.
I've broken the processing of the task up into smaller batches, but the way the data looks it's very difficult to tell what's still to be processed. I batch it using messages that each process a bite sized chunk of the data.
I have thought of using a Saga to control access to starting this process, with a Saga property called Processing that I set at the start of the handler and then unset at the end of the handler. The handler does some work and sends the messages to process the data. I check the value at the start of the handler, and if it's set, then just return.
I'm using Azure storage for Saga storage, if it makes a difference for the next bit. I'm also using NSB 6
I have a few questions though:
Is this the correct approach to re-entrancy with NSB?
When is a change to Saga data persisted? (and is it different depending on the transport?)
Following on from the above, if I set a Saga value in a handler, wait a while and then reset it to its original value will it change the persistent storage at all?
Seem to be cross posted in the Particular Software google group:
https://groups.google.com/forum/#!topic/particularsoftware/p-qD5merxZQ
Sagas are very often used for such patterns. The saga instance would track progress and guard that the (sub)tasks aren't invoked multiple times but could also take actions if the expected task(s) didn't complete or is/are over time.
The saga instance data is stored after processing the message and not when updating any of the saga data properties. The logic you described would not work.
The correct way would be having a saga that orchestrates your process and having regular handlers that do the actual work.
In the saga handle method that creates the saga check if the saga was already created or already the 'busy' status and if it does not have this status send a message to do some work. This will guard that the task is only initiated once and after that the saga is stored.
The handler can now do the actual task, when it completes it can do a 'Reply' back to the saga
When the saga receives the reply it can now start any other follow up task or raise an event and it can also 'complete'.
Optimistic concurrency control and batched sends
If two message are received that create/update the same saga instance only the first writer wins. The other will fail because of optimistic concurrency control.
However, if these messages are not processed in parallel but sequential both fail unless the saga checks if the saga instance is already initialized.
The following sample demonstrates this: https://github.com/ramonsmits/docs.particular.net/tree/azure-storage-saga-optimistic-concurrency-control/samples/azure/storage-persistence/ASP_1
The client sends two identical message bodies. The saga is launched and only 1 message succeeds due to optimistic concurrency control.
Due to retries eventually the second copy will be processed to but the saga checks the saga data for a field that it knows would normally be initialized by by a message that 'starts' the saga. If that field is already initialized it assumes the message is already processed and just returns:
It also demonstrates batches sends. Messages are not immediately send until the all handlers/sagas are completed.
Saga design
The following video might help you with designing your sagas and understand the various patterns:
Integration Patterns with NServiceBus: https://www.youtube.com/watch?v=BK8JPp8prXc
Keep in mind that Azure Storage isn't transactional and does not provide locking, it is only atomic. Any work you do within a handler or saga can potentially be invoked more than once and if you use non-transactional resources then make sure that logic is idempotent.
So after a lot of testing
I don't believe that this is the right approach.
As Archer says, you can manipulate the saga data properties as much as you like, they are only saved at the end of the handler.
So if the saga receives two simultaneous messages the check for Processing will pass both times and I'll have two processes running (and in my case processing the same data twice).
The saga within a saga faces a similar problem too.
What I believe will work (and has done during my PoC testing) is using a database unique index to help out. I'm using entity framework and azure sql, so database access is not contained within the handler's transaction (this is the important difference between the database and the saga data). The database will also operate across all instances of the endpoint and generally seems like a good solution.
The table that I'm using has each of the columns that make up the saga 'id', and there is a unique index on them.
At the beginning of the handler I retrieve a row from the database. If there is a row, the handler returns (in my case this is okay, in others you could throw an exception to get the handler to run again). The first thing that the handler does (before any work, although I'm not 100% sure that it matters) is to write a row to the table. If the write fails (probably because of the unique constraint being violated) the exception puts the message back on the queue. It doesn't really matter why the database write fails, as NSB will handle it.
Then the handler does the work.
Then remove the row.
Of course there is a chance that something happens during processing of the work, so I'm also using a timestamp and another process to reset it if it's busy for too long. (still need to define 'too long' though :) )
Maybe this can help someone with a similar problem.

NServiceBus: How to archive completed or terminated sagas

NServiceBus removes Saga data at least in the RavenDB persistens store when this.MarkAsComplete(); is called from the Saga itself.
Is there a built-in way to archive the Saga data when the Saga becomes completed or terminated? We need such a feature for traceability reasons.
You can put an internal flag in you saga data, set it to complete instead of calling MarkAsComplete and check it in your (saga) handlers.
(this way you can restart a saga if you want and you sagas will live forever)
Dose that make sense?
When using the rest of the Particular Service Platform, all actions on a saga get audited automatically, including the state that the saga was in when it completed.
ServiceInsight provides visualization of all of these state changes.

Multiple saga mapping of a single message

I need to map one message to multiple saga instances.
how can i do it?
i thought to an utility service that receives that message and sends copies of it to all saga instances. But this solution requires the knowledge from this service of all sagaIds.
This isn't currently supported on a single endpoint. If you want multiple sagas to handle the same message, that message needs to be processed by multiple endpoints.
Can you design your solution differently not to need multiple sagas to be invoked per message?

How to write handler for Error queues in NServiceBus Saga?

I have a situation where the Maxtries in my MSMQ is 5. After 5 times nservicebus sends the message to the Error que that I have defined. Now I want to perfomr some further action when this happens (I have to update status of some processes to Error)
Is it possible to write a handler in my Saga class to read these error queues?
Thanks in Advance
Haris
If your are using 2.x you may want to consider writing a separate endpoint where the error queue is its input queue. The downside to this is that the messages will come off the queue. Assuming you still want to store them, you'll have to push them off to a database or some other type of storage.
You could also write a Saga that polls the error queue to check for messages and updates the appropriate status. After each time you check the queue, you would need to request another Timeout.
In 3.0, you have more control over the exceptions, and can implement your own way to handle the errors. If you implement the interface IManageMessageFailures, you can do your work there.
As an alternative to the solutions provided by Adam, you can subscribe to events raised by ServiceControl which are raisesd when a messages is sent to the errorqueue. See the official documentation about this here: http://docs.particular.net/servicecontrol/contracts
Another approach would be the notification API as described here: http://docs.particular.net/nservicebus/errors/subscribing-to-error-notifications. It allows you to subscribe to certain events (not event messages) like "MessageSentToErrorQueue" directly on the endpoint, so you wouldn't need to consume the error queue.