SwedenDrew
SwedenDrew

Reputation: 61

Using NServiceBus in a synchronous API

I'm exposing an API to a vendor where that vendor requires the API to be synchronous. I however would like to use NServiceBus on the backend of it to make good use of our other architecture.
Is there a product/framework that can be used to do support this flow? Are there any thoughts/considerations in choosing this approach?

The API is as said synchronous where we will transform the request a bit and then put it on an NServiceBus queue for further processing by other systems.
After the message has been sent to a queue we should wait for the other system to complete its actions and be woken up again when the reply message is received.

Pseudo code:

void APICall(String someMessage) {
    var msgBusMessage = new { json = someMessage, ID = Guid.NewID() };
    NServiceBus.EnqueueMessage(msgBusMessage);
    var returnMessage = NServiceBus.WaitForReplyMessageWithID(msgBusMessage.ID);

    return returnMessage;
}

Upvotes: 1

Views: 507

Answers (1)

Mike Minutillo
Mike Minutillo

Reputation: 54819

NServiceBus has a feature called Callbacks which is designed to handle this type of interaction. It works almost exactly like the snippet you have provided. You send a request via NServiceBus and then get a Task that will eventually contain the response. You can await that task and return the result to the synchronous API.

To set it up:

  1. Add a reference to the NServiceBus.Callbacks package (in both the sender and the receiver endpoints)
  2. Enable callbacks by calling endpointConfiguration.EnableCallbacks(). If an endpoint returns replies but does not request request synchronous callbacks then you should use endpointConfiguration.EnableCallbacks(makesRequests: false)
  3. Any endpoint that makes callback requests should be made Uniquely Addressable endpointConfiguration.MakeInstanceUniquelyAddressable(someUniqueIdThatSurvivesRestarts). This allows the response message to be routed to the specific endpoint instance that is waiting for it.
  4. In the caller, use the following var response = await endpoint.Request<ResponseMessage>(new RequestMessage { ... })
  5. In the receiver create a handler for RequestMessage and return context.Reply(new ResponseMessage {...})

You can read more about this feature (including some caveats around when you should and shouldn't use it) in the documentation. There is also a sample showing the feature in use.

Upvotes: 2

Related Questions