A very common pattern for communication between applications is request-response. The synchronous fashion is currently well supported for instance by web service calls over HTTP. If you on the other hand want to use the pattern in an asynchronous fashion, then it suddenly becomes much harder.
There are a number of patterns for asynchronous request-response which we will look closer at in this article. They all include a Client that trusts a Middleman to eventually deliver a Request to a Server and that the Server Response will eventually be made available to the Client by the Middleman.
Pattern: synchronous execution, poll response
We will base our discussion on a pattern where the flow itself is asynchronous, but the Server is called synchronously and the Client have to poll for the response.
This pattern is described in the sequence diagram below.
A Client makes an asynchronous request to a Server by making a synchronous call to an intermediary Middleman. Eventually the Middleman makes a synchronous call to the Server and stores the response. The Client polls the Middleman until it gets the response.
The challenges
Exactly-once delivery
For some requests (such as a money transfer between two bank account) must not be be repeated unintentionally, so sending a request to the Middleman should not result in two identical requests sent to the server. This seemingly simple requirement is one of the hardest problems to solve in computer science: See the article The Impossibility of Exactly-Once Delivery.
As the Middleman you have to choose between at-least-once or at-most-once delivery. Now to some examples of this. A reasonable choice for the Middleman is at-least-once delivery, because then you can guarantee that you will deliver the request to the server, you "just" have to minimize the risk of duplicating the requests.
Examples of how requests can become duplicated:
- The Client posts a request to the Middleman. The Middleman sends an acknowledge that doesn't reach the Client. The Client will send a new identical request to the Middleman believing that the first request was lost. We have a duplicate.
- The Middleman sends the request to the Server. The Server executes the request and sends a response which doesn't reach the Middleman. The Middleman will resend the request to the Server believing that the first request was lost. We have a duplicate.
Risk of choking the Server
The Middleman can have a long queue of requests to the same Server and if it has no throttling mechanism it could flood the Server with more messages per second than the Server can handle.
Long execution time
If the Middleman sends a synchronous request to the Server and the execution time of the request is long, the Middleman will eventually have to cancel the operation and consider this a failed operation and maybe try again later. For HTTP synchronous requests the timeout for the request is 100 seconds in many systems.
Long execution times also takes up resources for the Middleman that could have thousands of requests that are taking more than a minute to execute, hindering the Middleman from delivering more requests to idle Servers.