"The approach chosen by the original implementer was to put a Spring DeferredResult into a static map and have the EventHandler complete the query/response rendering, but this is clearly the wrong place to do such processing as it’s a violation of SRP (amongst other things). "
However, I’m not so sure if it’s a violation of SRP. The responsibility (apparently) is to communicate state between client and server. To return correct state, the reply may need to wait for an event, and it’s fine for the component to do so.
However, it’s probably not the nicest solution.
First of all, it seems the API doesn’t seem to be compatible with eventual consistency. That’s the main issue here. But we’ll take that as a given, just for the sake of getting a solution.
The best is to return to the user based on the results of the Command Handler method. If a change is requested, and the command returns an OK, it is safe to assume the change was successful. So do a query, check if the result is as expected and otherwise apply the expected result.
If that is too complex, consider doing a query that returns the sequence number of the last event included in the model. From your command, return the sequence number of the events applied. Do queries until the sequence number is higher than the one returned. That’s when the deferred result “completes”.
These patterns are your typical sync-async solutions. They’re not beautiful, but needed when an async process is forced down a sync API.