JohT / showcase-quarkus-eventsourcing

Shows an example on how to use AxonFramework in conjunction with microprofile on quarkus
59 stars 11 forks source link

Getting Sagas to work #192

Open michelkaeser opened 1 year ago

michelkaeser commented 1 year ago

Hi Johannes

First, let me thank you for the work you put into this project. Getting started (with Quarkus + Axon) was quite easy with the help of it!

Currently I am trying to get Sagas to work but fail to do so on various edges.

Did you by any chance look into getting Sagas to work before?

JohT commented 12 months ago

Hi Michel,

you're welcome. I'm glad that it was helpful for you. I thought of also trying out Sagas here but got carried away by many other things I was curious about 😉. So no, I didn't even try to get Sagas to work.

Draft would take some time

I tried if I can come up with at least a draft for Sagas. But even this seems to take more time. One of the reasons for that is that I took an extreme approach back then to put Axonframework behind a boundary. I'd need to introduce a boundary for typical saga annotations and most probably the DeadlineManager.

Nevertheless, if you have some code (e.g. in a fork) then I could try to help you with the problems you encountered.

CdiResourceInjector

Regarding the two points you mentioned I'm not sure if I got them right. I'll try to answer them anyway 😀.

My custom implementation of the CdiResourceInjector does not depend on Quarkus. It depends on the Jakarta EE Standard "jakarta-enterprise-cdi-api".

What you probably mean is that my CdiResourceInjector implementation needs "full" CDI (Quarkus nearly "full" is ok) and isn't compatible to CDI-lite BeanContainer, the "smaller" version of the BeanManager. When refactoring the BeanManager to a BeanContainer the two methods createAnnotatedType and createAnnotatedType will be missing.

SagaLifecycle

With my already mentioned extreme approach of putting Axonframework behind a boundary I had a similar issue as far as I remember with the AggregateLifecycle. Static method calls are harder to replace (also for testing) and so I also put those calls behind the boundary. Have a look at AggregateEventEmitterAdapter.java. This introduces a lot of additional complexity that I won't do in a real world project. On the other hand it might be that the static calls need to be wrapped or configured somehow because AxonFramework provides some kind of context for them.

I hope I could help you somehow. Otherwise just send me an example and maybe I have an idea. I'm currently not able (time-wise) to add Sagas here. But if you got something to work I'm of course curious about that.

michelkaeser commented 3 months ago

Finally getting back to this after not touching it since then.

What I originally wanted to tell is that https://github.com/JohT/showcase-quarkus-eventsourcing/blob/master/showcase-quarkus-eventsourcing/src/main/java/io/github/joht/showcase/quarkuseventsourcing/messaging/infrastructure/axon/inject/cdi/CdiResourceInjector.java#L44 will throw exceptions when using sagas since Quarkus' arc container/bean manager does not implement these methods, see https://github.com/quarkusio/quarkus/blob/3be8518454c54b745e1e5fb44db65044d858082b/independent-projects/arc/runtime/src/main/java/io/quarkus/arc/impl/BeanManagerImpl.java#L241

Turns out this is not that big of a deal however since the parameter resolver can be used to inject dependencies on each saga handler rather than having them as injected fields.

It is important to note that https://github.com/JohT/showcase-quarkus-eventsourcing/blob/master/showcase-quarkus-eventsourcing/src/main/java/io/github/joht/showcase/quarkuseventsourcing/messaging/infrastructure/axon/inject/cdi/AxonComponentDiscovery.java#L67 should filter out @SagaEventHandler as these will be called twice otherwise (once via regular @EventHandler and once via @SagaEventHandler (as it is also a regular event handler)).

Given that, sagas can be used if working around these limitations is feasible.