Although I agree with @Gerard that if the command is dispatched and handled by this RaspberryPi “Bob” bought, then there’s no need to distribute the command bus. Hence, you could use a local version, like the SimpleCommandBus
or AsynchronousCommandBus
.
However, if the command is dispatched from the central server, you would want a distributed command bus solution like Axon Server.
Nonetheless, I think I have sad news for you. Although the tagging feature suggested by @Gerard would help you with ensuring the shortest route is taken when connecting an Axon Framework application with Axon Server, and thus shortening the networking distance of a given message, it does not provide you a means to dispatch a command to a specific instance.
As pointed out by @brunch earlier, Axon Server and Axon Framework ensure a given command handling node is consistently in charge of a specific aggregate’s command handlers.
It does so by using a consistent hashing algorithm for all (Axon Framework) nodes.
Then, when dispatching a command, Axon Framework extracts a “routing value” based on the command (this is provided by the RoutingStrategy
, as we described here in our Reference Guide), which will form the uniqueness that ensures commands containing the same routing value all end up at the same node.
This “routing value” represents a spot on the consistent hash ring. All command handling nodes, in turn, “own” a number of spots on the consistent hash ring (called the load factor). These spots are evenly distributed over the hash ring.
With this in place, whenever you dispatch a command, the follow steps occur:
- The command is pulled through the
RoutingStrategy
, resulting in a routing value.
- The routing value is added to the command and given to Axon Server.
- Axon Server knows of the registered command handlers and finds the right consistent hash ring representing the function that can handle the newly received command.
- Upon finding the set, it uses the added routing value to find the earliest match within the consistent hash ring. This match results in the address to route the command to.
As the consistent hash ring has a nearly endless supply of positions, we can add any number of nodes or remove them again, while maintaining the certainty that a command intended for a specific handler and aggregate is routed consistently.
The problem is that you as a user of Axon Framework or Axon Server cannot control which positions of the consistent hash ring go to what instance.
So, jumping back to your example, whenever you would register a Raspberry Pi, that would lead to registering command handlers with the central Axon Server installment. In doing so, the node’s handlers receive a random set of position in the consistent hash ring.
There are two ways how I think you can battle this, both with drawbacks:
- Use dedicated contexts per user. By doing so, the connection between Axon Server and Axon Framework would be unique per client. However, this will have massive implications for Axon Server, as it maintains several thread pools per context. Hence, a thread pool set per user would soon explode the amount of resources the system running Axon Server requires.
- Register command handlers manually, by adding the user identifier to the command name. This should proof doable, but honestly feels a little hacky. By doing this, you would essentially by pass the consistent hash ring implementation, as the uniqueness now comes from the
commandName
attribute instead of the “routing value.” The commandName
value is normally not something people adjust, as it defaults to the FQCN of the command you dispatch and handle. But, you can adjust the commandName
when subscribing handlers with the CommandBus
and could do the same when dispatching a command by constructing the CommandMessage
manually. The dispatching pointer is rather straightforward, but the command handler subscription pointer isn’t. It would force you to not use Axon Framework’s automated command handler registration through the annotations.
Long answer short. You could achieve specific routing towards an exact Axon Framework instance, but it isn’t built to support this cleanly.
However, it does again merit the question raised earlier: why?
Why would the Raspberry Pi your clients receive need to be an Axon Framework application that guards the user’s consistency boundary at all?