Durable Futures are a concept I've come up with to address the complexity inherent to a distributed, event-based architecture.
The code exploring the concepts is available on GitHub.
One of the most understood concepts in software development is request/response. In the simplest form, call/return, this conversation pattern between a client and a service, is the most commonly used idiom in software development.
var response = service.Method(request);
As programming languages have evolved, along with the common use of asynchronous programming models, remote procedure calls (RPC) via HTTP and other protocols, and message-based systems, the most understood pattern continues to be request/response.
var responseMessage = await httpClient.GetAsync();
var response = await client.GetResponse<TResponse>(new Request());
In each of these examples, await is a key enabler. Requests are sent asynchronously over a network connection to the remote service that produces a response which is then delivered to the client.
With HTTP, a connection is maintained by the client on which the response is sent. With MassTransit, a requestId and responseAddress passed to the service are used to send the response which is then read from the queue by the client bus and correlated back to the request.
The return type,
Task<T>, is a C# language feature that represents a future. It's a reference type which means it is only accessible by reference. Since
Task<T> is a future, it promises to deliver at some point:
- An exception (faulted)
- A task canceled exception (canceled)
I'm intentionally ignoring
ValueTask<T> for now. It behaves similarly but has a few restrictions, one of which being that it should only be evaluated once.
await, writing asynchronous code was significantly more complex. Continuation passing was commonly used, resulting in deeply nested code that was difficult to understand and even more difficult to debug. Without a doubt,
awaitare two of the best keywords in C#.