Aggregate with external persistence (case model/camunda)

I am working on a concept to combine Axon/CQRS aggregate with a camunda process execution.

I am running a CMMN case instance on camunda. In short, it is an management frame for a business case and all tasks and processes that are run during the procesing of this business case. Activities in a CMMN instance have a defined state model (enabled/disabled/active).The case Instance has its own persistence, provided by the camunda framework), so every state change is transactionally persisted.

In an event driven microservice world this causes the classic problems: we receive requests and state changing commands from the outside world, but (re-)evaluating the concrete state of the instance (is this activity really active anymore? Do I have to disable this possible task because a constraint became invalid?) take time, so we deal with concurrent changes, long running transaction, optimistic locks and this odd feeling that a query listing “all available tasks” might not be really the truth but only the outdated truth from some seconds ago.

I am working on a concept where I have a “backing bean” that represents a case instance and all its states and data and takes control of ordering reevaluations and stage changes and also provides a query api so the “last known state” or at least the information that a reevaluation is still in progress and the state might be dirty.

I believe that an aggregate would be a good possible representation of such backing bean. External requests/events can be treated as commands, the case instance id is the identifier and I can keep a state-backup in the aggregate to block incoming events when a reevluation is in progress. I can have view-presentaions for queries and handle long running transactions in sagas.

I didn’t start implementing, but I guess this might work.

My problem is the storage of data/state. Since the camunda engine works strictly transactional, all information of this bounded context is persisted anyway. I dont want to have event replay, I cannot crate a fresh instance of the case every time and run the time consuming recurring state evaluations.
So I can turn eventsourcing of. But from my understanding axon then would require me to store the aggregate entity, which is in the best case purely redundant, in the worst case a mismatch between the “truth” (the case instance) and the last known aggregate state.

I had a look at he internal implemantion and have two theories that (if you read this far and are able to follow me) I’d like to discuss:

1.) (the easy one) when all state changes on the case instance are handled with sagas, they are not replayed if events re-occur?
2.) I can use a custom AggregateFactory that creates the state of the aggregate by loading the case instance and setting all relevant properties on the Aggregate when the next event is handled.

So, is it possible to configure an aggregate in a way that its state is not stored in an event stream and not stored in an entity but read from an external persistent “thing”? If so, will I still be able to have “regular” aggregates in my system, or will this special factory be applied for all aggregates?
Is the whole concept a misuse of the aggregate/axon way?

I am happy to hear your thoughts. I believe this is challenging but if its able to work, it might actually become a good pattern to handle case state in an eventdriven world.

Thank you for reaching this line!

Jan

Hi Jan,

we’ve had a few conversations with the Camunda guys a little while ago about this. Meanwhile, Martin Schimak was doing a proof-of-concept to implement Sagas using Camunda (https://github.com/plexiti/axon-camunda-poc). I have to say that this seemed a very good fit. An Axon Saga was just used to trigger processes in Camunda, which in turn is responsible for making decisions based on this triggers.

Implementing Aggregates as processes is something that feels less natural to me. That isn’t based on prior experience, though.

Hope this helps,
Allard