Distributed Application Architecture Patterns

4.3 Asynchronous Request–Reply

Asynchronous two-way communication

This pattern is based on Request–Reply by Hohpe et al. [4, p. 147, 60], Asynchronous Request–Reply by Microsoft [61], Asynchronous Request–Response by Hohpe [62], Request-Response Communication by Newman [3, p. 104], and partly on the Messaging pattern by Richardson [20, p. 87, 59] and the Decoupling Middleware pattern by Nygard [12, p. 117].

The patterns have varying implementations but share the same structure and purpose. An overview is given below.

See also Message Broker.

4.3.1 Context

Synchronous messaging has become a bottleneck, but using only Publisher–Subscriber (see § 4.2) or Queue-Based Load Levelling is not an option, as either

  1. The client expects a response

  2. One of the communicating parties cannot use a messaging broker due to technical limitations (e.g. a web browser), or when long-running connections are not feasible

4.3.2 Solution

There are three potential ways to implement this pattern.

  1. Use a message broker (see § 7.2) and configure two queues: one for the request and one for the response. The sender sends a message to the request queue and waits for a response on the response queue.

  2. Use synchronous communication to send the request, then use polling to check for a response on a pre-determined endpoint. This option is less efficient as there will be more communication overall, but it might be easier to implement with existing infrastructure or tools. The receiver can improve efficiency by replying with an estimate on the request completion [61].

  3. Use synchronous communication and a callback mechanism. The sender sends a request and a callback address. The receiver processes the request and sends the response to the callback address. [62]

Asynchronous Request–Reply

4.3.3 Potential issues

Compared to synchronous communication, this pattern brings increased latency and complexity. If implemented using synchronous calls, Retry logic (see § 7.3) might need to be employed to handle transient failures.

Using synchronous communication is faster, simpler and more efficient if the requirements allow it.

Using this pattern to communicate with multiple parties may result in requests being processed out of order. This can be mitigated using a Correlation Identifier [4, p. 154, 63].

See also § 4.2.3.

4.3.4 Example

Creating an order in ExampleEshop is a complex operation implemented as a distributed transaction, which can take longer than the timeout of a synchronous call. However, they want to provide feedback to the user as soon as possible. Still, these updates do not have to be long-term, as analytics showed that users stop refreshing the page once they receive confirmation that their payment is through and an estimated delivery time.

Thus, for a simple implementation, they opted to poll the server periodically to check the order status in the initial phases when many changes are happening. Once the order is confirmed, the frontend stops polling and informs the user that they will receive further updates via email.

4.3.6 Further reading