Web service integration - rebus-org/Rebus GitHub Wiki
One scenario where Rebus (and NServiceBus, MassTransit, etc for that matter) really shines, is when your application wants to communicate with an external web service.
Why is that?
Because usually web services work by letting you communicate directly with them, possibly using some form of HTTP transport (hence the "web" in web services), using either SOAP or REST as a protocol. I.e. there's no kind of middleware involved, you're directly requesting stuff from some external party.
The crux is that communicating directly with an external party imposes their availability and reliability problems on you! So, if there's a hiccup somewhere, either on the internet or on their end, then you have a problem as well...
How can Rebus solve that?
By following a rule, where all communication with external parties is done through a Rebus service using request/response messaging, you can benefit from automatic retries and error handling. This means that if there's a hiccup somewhere, then the automatic retries will most likely ensure that the request succeeds - and if it doesn't (if the external party is just plain broken), then the request will be moved to the service's error queue, allowing you to retry the message some time in the future.
One thing to be aware of
All distributed systems are subject to the fundamental rule that you're stuck with exactly one of these two delivery guarantees:
- zero or once delivery
- at least once delivery
In other words: no matter how hard a queueing system tries, it cannot guarantee anything but one of these two - which is why queueing systems usually opt for at least once delivery, which in turn can cause the same message to be delivered to your application twice.
If you need to ensure a strict exactly once delivery guarantee, there's some work to be done on your end: You must ensure that you're idempotent, and then, some kind of retry mechanism must be in place to overcome the case where delivery fails.
This is just the way it is. And this is also the way it is for the external party, that you're integrating with.
The consequence
If you're just querying data, then there's probably no problem - your request/response service can just query the web service in the request handler, and bus.Reply
with the received response. If the request was ever to be processed twice because your machine decided to reboot between having received the response and calling bus.Reply
, then the integration service would still just return one reply, and the world would not be affected (badly) in any way.
There might be a problem, however, if the external web service is a command processor of some kind, e.g. something that processes PlaceOrderCommand
- in this case, it is important that the web service is idempotent! One way to achieve this, is that the web service accepts some kind of order ID or transaction ID or just a plain command ID, and then ensures that it doesn't process the same PlaceOrderCommand
twice.
So, in case your external web service does not provide a mechanism to implement idempotency, then the external party has a problem. And that's a fact, so you might as well just tell them that either:
- they go and implement idempotency, or
- they take reponsibility if they receive the same order twice
It's their call.