So I have a ReST api that has a service injected which then submits a command. Currently, I’m using the callback version of sending commands with the ReST api being asynchronous. This works well.
I’m exploring the scenario where the ReST API can be truly fire and forget - so here’s the flow I’m trying to model the flow:
User submits POST to /api/greetings
Controller calls service api which submits a command using the .send(Object) variant
Return the command id to the client with a 202 Accepted status
Once command is processed and events raised, event has the command Id as metadata. Event and metadata are pushed over a websocket channel.
For (4), I have hooked up the CommandHandlerInterceptor to copy over the command identifier to the event metadata.
I’m hitting an issue with 3 - basically getting access to the command id after sending the command. I can solve it with introducing a separate commandId property in my commands and having custom interceptor/provider to copy that custom property into the metadata.
Just that it seems like taking a shotgun to kill an ant :). Secondly, the command id etc are not really properties of the domain - it’s infrastructure - so I’d rather not mess my domain for that.
I’ve looked at commandDispatchInterceptors - which will let me modify the command before it gets sent out (and gets a CommandMessage object) but there doesn’t seem a way out other than introducing a commandId attribute in my command object. This gets me almost what I want but I still need to introduce a base class for commands with a commandId attribute.
Is there a way to do this without introducing the base and an extra property in the commands?
I’ve been staring at it for a few hours and not seeing a solution - and so I’m here
each Message contains an identifier. You could use that identifier in your callback. You can use a CommandHandlerInterceptor to attach the command id as correlationID in the meta data of generated events.
You seem to be looking for “fire and forget”. What’s the goal you’re trying to achieve? What’s wrong with sending a 200OK based on the outcome of command handling?
each Message contains an identifier. You could use that identifier in your callback. You can use a CommandHandlerInterceptor to attach the command id as correlationID in the meta data of generated events.
I have this working without issue. I’m having trouble on the command side of things basically getting access to the command id after the command is dispatched:
ReST Controller → create a command object → send a command → return the command id to the client.
At the moment, this is mostly academic - I have the scenario where the ReST API is async and returns a response once command handling is complete working. I’m trying out a scenario where the client gets an OpID once a command is dispatched and then waits for events with the same OpId.
-Raghu
Can you share the stub of your code as I am trying to understand how is this connecting to CommandHandler logic and the controller call. I am doing something like this. But messageIdentifier is not stored with the event so whats the benefit of sending commandId to the client?
But messageIdentifier is not stored with the event so whats the benefit of sending commandId to the client?
Yes - but it’s available as metadata when the event is raised (it’s also stored in the eventstore as well).
Configure a CommandHandlerInterceptor to copy the command id as the Event metadata
` @Bean
public CommandHandlerInterceptor commandHandlerInterceptor() {
AuditingInterceptor auditingInterceptor = new AuditingInterceptor();
auditingInterceptor.setAuditDataProvider(new CorrelationAuditDataProvider());
// elided…
return auditingInterceptor;
}
`
In my case, for events I send a websocket push - you can declare a parameter of type MetaData and you will get the associated metadata in the event handler. Here’s what my code for the push looks like:
` @EventHandler
public void handleEvent(GreetingUpdated ev, MetaData m) {
Message payload = new Message(ev, m);
log.info(“Publishing websocket message: {}”, payload);
this.messagingTemplate.convertAndSend(“/topic/greeting”, payload);
}