Bojan Vukasovic
Bojan Vukasovic

Reputation: 2268

Axon - Projection or event enricher?

I have following setup:

  1. HTTP request arrives on REST endpoint and I receive it in my Application Service.
  2. Application service maps request to command C1 and forwards it to aggregate using commandGateway.sendAndWait(new C1(restPostBody));.
  3. Aggregate is loaded from repo, new command is applied and new event is produced an saved to store.
  4. At this point in time, I need to enrich this event and use it as response of REST call.

So far I can see this options:

  1. Use view projector, and project new event to create view model that can be forwarded as response in REST call. I guees here I would need to use queryGateway.subscriptionQuery(... and sqr.updates().blockFirst() for waiting for event to be processed by projector and then create response. Also, I guess this should be synchronous, since projection could get out of sync if system fails between storing event to DB and storing projection to DB?

  2. Use some event enricher after event is published from aggregate and add needed properties to it and add response to REST call. This is similar to Projection, but in this case I would not save it to DB, since only time I need the data is as response to REST endpoint at the time command is issued. This should be definitelly synchronous, since if something fails, I would loose response. In case of async - I would need to have Aggregate handle duplicate events, and still emit events to event enricher but without storing to db. This seems to make things a lot complicated.

Are there any best practices related to this?

UPDATE

what I'm having currently is:

@Autowired
    public void configure(EventProcessingConfigurer configurer){
        configurer.usingSubscribingEventProcessors();
    }

for synchronous Event processing in aggregate and view-model. Then I can query view model using (looks a bit ugly - is there better way?)

try {
            sc = queryGateway.query(new MyQuery("123", "123),
                    ResponseTypes.instanceOf(SomeView.class)).get();
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        catch (ExecutionException e) {
            e.printStackTrace();
        }

And I can return this SomeView as response on REST api.

Upvotes: 2

Views: 1174

Answers (1)

Steven
Steven

Reputation: 7275

So, @bojanv55, you're trying to spoof your application to be a synchronous set up, whilst the command-event-query approach with Axon Framework enforces you to go the other way.

Ideally, your front-end should be compliant to this situation. Thus, if you hit an end point which publishes a command, then you'd do a fire and forget. The events updating your query model will be pushed as updates, as they happen, to the front-end. So shortly, embracing the fact it's asynchronous should, in the end, make everything feel more seamless.

However, that's easier said then done; you're asking this question with a reason of course. I personally like the usage of the subscription query, which you're also pointing towards, to spoof the operation to become synchronous.

This repository by Frans shows how to do this with Axon Framework quite nicely I think.

What he does, is handle the REST operation and first dispatching a subscription query for the thing you know will be updated pretty soon. Secondly, the command is dispatched to the aggregate, the aggregate makes a decision to publish an event and the event updates the query model. The query model update then constitutes in an update being emitted towards your subscription query, allowing you to only return the result as soon as the query model has actually be adjusted.

Concluding, I'd always recommend my first suggestion to embrace the asynchronous situation you're in. Secondly though, I think the subscription query solution I've just shared could resolve the problem you're having as well.

Hope this helps you out!

Upvotes: 3

Related Questions