How to implement pub-sub pattern with Axon?

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. For new events that occurred while the PubSub service was down, replay is great at ensuring every event was processed.

So how to ensure PubSub event handlers process each event exactly once?

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

Thanks for your help!