So it has come time to tackle this async response problem we’ve had since adapting this architecture. That is, when the web site submits a request, we respond with 202 and allow the command to pass through all the services it needs to get the job done. The problem is that the frontend doesn’t know if it actually succeeded or not.
The common solution to this is to submit the command and then subscribe to a response queue and wait for some sort of response from the server. What I’m investigating as a more real-time solution is the use of SignalR, now that it’s available in .net core. In this scenario, we have a couple options, I think:
- Subscribe to a message hub and receive all messages from it. The frontend would continue to submit requests over the REST API separate of the message hub and just handle all messages from the server and sort out what it cares about. Complicated.
- Have the frontend submit requests over the message hub which sends messages over NSB and then issues a callback that is run when a specific event is received. Less complicated.
What I’m envisioning is that the _session.Send() method allows a transient handler to respond to events that have the same correlation ID as the original request message. Maybe something like this:
public async Task SendMessage(MyRequest request)
{
var user = await _userStore.GetById(request.UserId);
if(user == null)
throw UserDoesntExistException(request.User.Id);
var command = new MyCommand(){ ... }
var options = new SendOptions();
options.RegisterCallback<Event1>(Stage1Update);
options.RegisterCallback<Event2>(Stage2Update);
await _bus.Send(command, options);
}
public async Task Stage1Update(MyResponse response)
{
// assuming "caller" is captured as part of this closure...
Clients.Caller.SendMessage(
"SomeHandler",
new { Type = "Stage1Update", Result = response })
}
public async Task Stage2Update(MyResponse response)
{
// assuming "caller" is captured as part of this closure...
Clients.Caller.SendMessage(
"SomeHandler",
new { Type = "Stage2Update", Result = response })
}
So what this would do is send the command and then assign callbacks that are execute for each event type. This seems redundant because I could just create event handlers in the normal fashion, but those would respond to all of those events which is problematic. The reason being, I will have multiple frontend clients sending different messages for different reasons and each of them only wants updates on the messages that were sent that respective client.
I think you get the idea.
So does this functionality already exist in some fashion? If not, do you have any suggestions?
It looks like this is has already been thought of in some capacity (Near Real-Time Transient Clients • NServiceBus Samples • Particular Docs), but the example is only a global message and I need something a bit more localized. The only other thing I could think of is using the example in the link above along with a cache of some sort where I can map a message id to a client and then the handler would just use that to figure out which client to send the messages to.