Summary
This document explains how to setup a SAGA to SAGA request Response pattern. Bus.Reply is used, as ReplyToOriginator is not supported. We will simulate a service receiving an order, then sending it to an Order Service, which then has a request/response pattern to process payment.
- We will create 3 endpoints, OrderSender , OrderService, PaymentService
- We will configure an order to send an initial Order from OrderSender to OrderSaga
- We will then configure OrderSaga to send a Request/Response to PaymentSaga
- Note, I have message correlation as well. This is needed for ReplyToOriginator to work between Saga’s from a timeout.
Saga to Saga Request/Response supports Bus.Reply, however do not use it in TimeOut handlers, as it will try reply to the timeout queue.
ReplyToOriginator also works, when you need to call the originating Saga, however there were issues on the bug report https://github.com/Particular/NServiceBus/issues/2018. However you can get it working by doing two things:
- Ensure the Calling Saga outlives the Called Saga (Create a Long TimeOut that marks Saga completed in Calling, Create a shorter timeout in the Called Saga that MarksItComplete)
- Add this code to the ProcessOrderHandlerConfigureHowToFindSaga.cs
You can download the source code at:
git@bitbucket.org:romiko/sagatosagarequestresponse.git
or
https://romiko@bitbucket.org/romiko/sagatosagarequestresponse.git
Just enabled NUGET package restore J
TimeOuts and responding to the original calling (originator) saga
Never use Bus.Reply within a TimeOut handle in the Saga, as it will try to reply to the timeout queue, as Bus.Reply will always respond to the source of the LAST incoming message.
To get ReplyToOriginator working between Saga’s, you need to:
- Ensure the called Saga (ProcessOrder) lives LONGER than the called (Payment), by using timeouts in both sagas
- You need to add a correlation
This is the message pattern with timeouts and a polling pattern, which you can run indefinitely if ever needed.
Create three endpoints
- Click New endpoint
- Create an OrderReceiver, as an NServiceBus Host. Do the same for OrderSaga and PaymentSaga
- Your canvas will look like this
Send a message from OrderReceiver to OrderSaga
So now we will simulate a service (OrderReceiver) that receives orders on a backend system and then sends them to our OrderSaga for long running transaction processing
- Click the OrderReceiver and click “Send Command”
- Set the Service name to Orders (Domain) and the command ProcessOrder
Your canvas should look like this
- Click the undeployed component and select Deploy
-
Select OrderSaga as the destination and click Done
Your canvas should look like this, with a bit of interior design J
- Edit the ProcessOrder message and add the following properties
OrderId
Amount - Open the ProcessOrderSender.cs file under the Orders folder, we will configure it to send 3 orders. We will implement IWantToRunWhenBusStartsAndStops
Note that I am not in the infrastructure folder, as this is generated code.
- Build the solution
Configure the OrderSaga as a Saga and Message Correlation
Great, so now we have the minimum need to set the OrderSaga endpoint to a real Saga, as a SAGA MUST have a message to handle. In this case ProcessOrder.
- Click the ProcessOrderHandler and click “Convert To Saga”
- This will open the ProcessOrderHandlerConfigureHowToFindSaga.cs file. Build the solution, so that partial classes are generated.
- We want to correlate order messages based on the orderId to the correct Saga instance. So here we will set the properties on how to find it. Add the following code:
- Open the file ProcessOrderHandlerSagaData.cs and add the OrderId, set the property to Unique, as this is how the Saga will correlate messages to the correct instance.
Excellent, so now we have correlation established between the OrderReceiver and the OrderSaga. So if ever the Saga receives order updates for the same order, the infrastructure will no which instance to send the processorder command to.
Configure Saga To Saga Command
Here we will configure the OrderSaga to send a message to the PaymentSaga, then we will update the PaymentSaga to become a Saga.
- Click the ProcessOrderHandler and click SendCommand
- Name the command ProcessOrderPayment
- Click Copy to Clipboard. This will then open the ProcessOrderHandler.cs file. Paste the code.
- Open the Canvas, it should look like this
- Click the ProcessOrderPaymentHandler, and Click Deploy.
- Select the Payment Saga, as this will handle the ProcessOrderPayment Request.
- Your canvas will look like this. BUILD SOLUTION
- Let’s CONVERT PaymentSaga endpoint to a Saga, as we have the minimum needed to do this!
WARNING: NEVER convert an endpoint to a saga unless it has at least one message handler, else it cannot implement IAmStartedByMessages interface. You would have to wire it up manually, since the Infrastructure code generator will not know how.
- Click ProcessOrderPaymentHandler and click Convert to Saga…
- This will open the ProcessOrderPaymentHandlerConfigureHowToFindSaga
- Build the solution, to auto generate the Saga partial classes and infrastructure
-
We want the payment instance to correlate to the correct order Id, so add this:
Build the solution! We added properties so ConfigureHowToFindSaga will compile J
Configure Saga To Saga Response and Bus.Reply
- Open the ServiceMAtrix Canvas, confirm your canvas looks like this
notice the icon for saga’s has a circle in it with a square. - Click the ProcessOrderPaymentHandler in the payment Saga and click Reply with Message…
- Click Ok
- Copy the code to Clipboard
- Click the Copy To Clipboard, note the mouse pointer will show as busy, however you can still click copy to clipboard.
- This will open the ProcessOrderPaymentHandler.cs, paste the code here. Put in a Thread.Sleep to simulate a credit card payment.
- Your canvas will look like this now
- Add the following code to ProcessOrderHandler.cs file
- Build the solution
Testing the solution
Following the following in Order, so the msmq’s are created in the correct order, to avoid race conditions on the first time is starts.
- Start the SagaToSagaRequestResponse.PaymentSaga
- Start the SagaToSagaRequestResponse.OrderSaga
- Start the SagaToSagaRequestResponse.OrderReceiver
You should see
And
In ServiceInsight we see:
Source Code
You can download the source code at:
git@bitbucket.org:romiko/sagatosagarequestresponse.git
or
https://romiko@bitbucket.org/romiko/sagatosagarequestresponse.git
Just enabled NUGET package restore J