0
votes

We have a multi-step process we'd like to implement using a pub-sub pattern, and we're considering Axon for a big part of the solution.

Simply, the goal is to generate risk scores for insurance companies. These steps would apply generally to a pub-sub application:

  1. A client begins the process by putting a StartRiskScore message on a bus, specifying the customer ID. The client subscribes to RiskScorePart3 messages for the customer ID.

  2. Actor A, who subscribes to StartRiskScore messages, receives the message, generates part 1 of the risk score, and puts it on the bus as a RiskScorePart1 message, including the customer ID.

  3. Actor B, who subscribes to RiskScorePart1 messages, receives the message, generates part 2 of the risk score, and puts it on the bus as a RiskScorePart2 message, including the customer ID.

  4. Actor C, who subscribes to RiskScorePart2 messages, receives the message, generates part 3 of the risk score, and puts it on the bus as a RiskScorePart3 message, including the customer ID.

  5. The original client, who already subscribed to RiskScorePart3 messages for the customer ID, receives the message and the process is complete.

I considered the following Axon implementation:


A. Make an aggregate called RiskScore

B. StartRiskScore becomes a command associated with the RiskScore aggregate.

C. The command handler for StartRiskScore becomes Actor A. It processes some data and puts a RiskScorePart1 event on the bus.

Now, here's the part I'm concerned about...

D. I'd create a RiskScorePart1 event handler in a separate PubSub object, which would do nothing but put a CreateRiskScorePart2 command on the command bus using the data from the event.

E. In the RiskScore aggregate, a command handler for CreateRiskScorePart2 (Actor B) would do some processing, then put a RiskScorePart2 event on the bus.

F. Similar to step D, a PubSub event handler for RiskScorePart2 would put a CreateRiskScorePart3 command on the command bus.

G. Similar to step E, a RiskScore aggregate command handler for CreateRiskScorePart3 (Actor C) would do some processing, then put a RiskScorePart3 event on the bus.

H. In the aggregate and the RiskScoreProjection query module, a RiskScorePart3 event handler would update the aggregate and projection, respectively.

I. The client is updated by a subscribed query to the projection.


I understand that replay occurs when a service is restarted. That's bad for old events because I don't want to re-fire commands from the PubSub handlers. It's good news for new events that occurred while the PubSub service was down.

EDIT #1:

I've considered using an Axon saga, which would be great. However, the same questions still exist even if PubSub is a saga:

How to ensure PubSub event handlers process each event exactly once, even after a restart?

Is there a different approach I should be taking to implement a pub-sub pattern in Axon?

Thanks for your help!

1
In addition to running the standard AxonServerEventStore for normal events, is it possible for us to run a SimpleEventBus that is only for saga-related events? How would we do that?Jonathan M
Or is some use of the @AllowReplay(false) annotation advisable? I tried it with @SagaEventHandler, but it didn't seem to work. Does it only work with normal @EventHandler methods?Jonathan M

1 Answers

0
votes

I think I can give some guidance in this area.

In your update you've pointed out that you envisioning the usage of a Saga to perform this set up. I'd however would like to point out that a Saga is meant to 'Orchestrate a Complex Business Transaction between Bounded Contexts/Aggregates'. The scenario you're describing is not a transaction between other contexts and/or aggregates, it's all contained in a single Aggregate Root, the RiskScore.

I'd thus suggest against using a Saga for this situation, as the tool (read: Saga) is relatively heavy wait for what you're describing.

Secondly, from the steps you describe from A to I, it looks as if the components described in steps D and F are purely there to react with a command on the event. Thus, they perform zero business functionality, taking that assumption.

Taking my initial point of a transaction contained in a single Aggregate Root and the fact no business functionality occurs on the dispatching of the command back in to the aggregate, why not contain the entirety of the operation within the RiskScore aggregate?

You can very easily handle the events an Aggregate publishes with the @EventSourcingHandler and on that method apply another event. Or, if you would like to be 'pure' about segregating state updates and apply events, you could just apply more events for the separate risk-score steps there after.

Any how, I don't see why you would need to hold tightly towards the pub-sub pattern. I'd take a solution which resolves the business needs as best as possible. That might be an existing pattern, but could just as well be any other approach you can think off.

This is my two cents to the situation, hope they help!