Enhancing Order Processing with Orchestrated Sagas
Explore how to create message handlers and update the composition root in Saga order creation in the Order Processing module.
We'll cover the following...
Creating the message handlers
As discussed earlier, we will be listening for the OrderCreated
integration event from the Order Processing module as our trigger. The design of the actual handler itself is just like the others, but we start a saga instead of creating a data cache or executing some application command:
func (h integrationHandlers[T]) onOrderCreated(ctx context.Context, event ddd.Event,) error {payload := event.Payload().(*orderingpb.OrderCreated)// compute items and totaldata := &models.CreateOrderData{OrderID: payload.GetId(),CustomerID: payload.GetCustomerId(),PaymentID: payload.GetPaymentId(),Items: items,Total: total,}return h.orchestrator.Start(ctx, event.ID(), data)}
The preceding code starts the saga, which, as its first action, will locate the next step it should execute and then run it. The orchestrator does not keep the sagas running or in memory. After each interaction, the orchestrator will write the saga context into the database and return it to the reply message handler; as we mentioned earlier, they are reactive.
This is made clear with the following code, which registers the orchestrator as a reply message handler:
func RegisterReplyHandlers(subscriber am.ReplySubscriber,o sec.Orchestrator[*models.CreateOrderData],) error {h := am.MessageHandlerFunc[am.IncomingReplyMessage](func(ctx context.Context,replyMsg am.IncomingReplyMessage,) error {return o.HandleReply(ctx, replyMsg)},)return subscriber.Subscribe(o.ReplyTopic(),h,am.GroupName("cosec-replies"),)}
The orchestrator handler replies directly, so it is not necessary to create another reply handler intermediary in the module’s composition root. We only need a handler for the reply message that calls the orchestrator to handle the reply.