Reputation: 24527
I have a pretty nice idea for fine granular API command handling.
Our web API should provide single simple update
endpoint, but you can provide multiple commands to it. Something like this:
POST /myAggregate/12345/update
[
{ command1Name: "command1Data" },
{ command2Name: "command2Data" },
{ command3Name: "command3Data" }
]
Within Axon this seems quite difficult to handle. Especially in combination with @AggregateVersion
.
My first idea was to have a new UpdateWrapperCommand
. which internally has a List commands
. And then within the Aggregate, you use reflection to call the correct @CommandHandler
methods:
class UpdateWrapperCommand {
List commands;
}
@Aggregate
class MyAggregate {
// id, version, constructor, etc. pp.
@CommandHandler
public void handle(SomeCommand cmd) { ... }
@CommandHandler
public void handle(UpdateWrapperCommand cmd) {
// iterate over cmd.commands
// iterate over this.getClass().getMethods()
// find correct method(s), and invoke it
}
}
But when the @CommandHandler
s also use @MetaData
and/or Spring Bean injection, then it's getting really hard.
My second idea was to simple call commandGateway.send
in a loop. But that blows up, because @TargetAggragateVersion
must be set for every command, and you have to wait for every command to complete, before sending the next one. That's not nice.
Do you have any ideas for that?
It should load the aggregate once and then run all commands.
And maybe even have some transaction-like behavior: Apply all resulting events, or none.
Upvotes: 2
Views: 1594
Reputation: 7275
I think you're best bet to get this resolved right now, without the need to wait to the issue you've added to Axon Framework's issue tracker, is to add an External Command Handler.
The External Command Handler is just a regular Component with an @CommandHandler
annotated function on it. That method would handle your UpdateWrapperCommand
and know the works to issue separate commands for every command payload contained it.
The loading optimization of the Aggregate as you're suggesting is however really tied to implementing a Batch Command solution. Although this is definitely doable in the framework, this feature isn't in place yet. I'd suggest you keep tracking the issue you've created to follow the progress of it.
Hope this helps you out Benjamin!
Upvotes: 1
Reputation: 121
If the transaction means that is all or nothing, then probably the boundaries of each commands are not well modelled.
Without understanding of domain I would say options are:
1 Wrap all the commands in only one and apply to one handle-all aggregate.
2 Apply all the commands independently and in case of any failure then apply compensating actions.
3 Not to use commands at all and just apply the transactional logic over something simpler.
Upvotes: 0