Gregor's Ramblings
Home Patterns Ramblings Articles Talks Download Links Books Contact

Will the Real Asynchrony Please Stand Up?

May 15, 2005

Recent Ramblings
DDD - Diagram Driven Design
What Does It Mean to Use Messaging?
A Chapter a Day...
EIP Visions
Clouds and Integration Patterns at JavaOne
My First Google Wave Robot
Google I/O
Into the Clouds on New Acid
Design Patterns: More than meets the eye
Reflecting on Enterprise Integration Patterns
Google Gears Live From Japan
Double-Dipping: OOPSLA and Colorado Software Summit
Bubble 2.0
Enterprise Mashup Summit
Facebook Developer Garage
Mashups Tools Market
Mashups == EAI 2.0?
Mashup Camp
I Want My Events
ALL RAMBLINGS

Asynchronous Invocation Patterns

We all know by now that synchronous, object-oriented applications are a thing of the past. If you want to be cool these days you have to be asynchronous. Hey, even Starbucks figured that out! Anyway, our last project had "asynchronous service invocation" already in the list of the requirements so very little convincing was necessary. Being a huge fan of asynchrony and patterns, I quickly started to recite asynchronous invocation patterns. Having learned that quoting other people's books reduces the amount of eye rolling and sighing, I described the patterns in Chapter 8 of Remoting Patterns. This chapter has a nice side-by-side comparison of asynchronous interactions between systems, such as Fire-and-Forget, Callback, Polling.

Patterns Everywhere

The great thing about patterns is that they often apply to different contexts and levels of abstraction. As such they allow us to transfer knowledge and experience gained in one area to another area or another level of abstraction. This holds particularly true in areas such as message flows or workflow processing that can span domains as diverse as fluid dynamics, EAI messaging, manufacturing optimization, coffee shops, or composite services.

Interaction patterns enjoy a wide range of applicability as well, particularly in the world of event-driven applications and message-based integration. Unfortunately, this wide applicability can increase the chance of misunderstandings, especially if we deal with remote communication. When I tell a coworker that I use "Asynchronous Callback" for my Web service he or she might think that I use an asynchronous client API. Another colleague who is developing a service provider might think that I want to invoke his service code through threads or delegates. Another person yet might think to use message-oriented middleware between components as supposed to HTTP. These examples portray (at least) three different views that exist when we look at communicating systems:

Let's look at asynchrony from all three viewpoints: (Depending on the nature of the conversation the roles may be more manifold than simply consumer and provider but let's stick with those two for now to exemplify an entity that sends a message and expects a response, and an entity that accepts requests and returns response, respectively.)

Asynchronous Client Library

It is very common for Web services frameworks to offer asynchronous client libraries. This functionality is often already baked into the client stub that the toolkit generates from the provider's WSDL. For example, on the .Net platform the client proxy generates three methods for every operation listed in the WSDL document. For example, if the provider exposes an operation GetLoanQuote, the client proxy exposes the methods:

public LoanQuoteReply GetLoanQuote(LoanQuoteRequest LoanQuoteRequest) {...}
public IAsyncResult BeginGetLoanQuote(LoanQuoteRequest LoanQuoteRequest, AsyncCallback callback, object asyncState) {...}
public LoanQuoteReply EndGetLoanQuote(IAsyncResult asyncResult) {...}

The BeginGetLoanQuote and EndGetLoanQuote methods allow the consumer to invoke the service asynchronously. Or do they? Well, it depends on your point of view. These methods are wrappers around the BeginInvoke and EndInvoke methods in the SoapHttpClientProtocol base class and provide for an asynchronous (i.e. non-blocking) programming model for the client application. This type of asynchrony is quite useful to keep the client application from sitting in a loop waiting for a response from a remote service. In fact, it is highly recommended to use the BeginXXX and EndXXX methods (and in .Net 2.0 we get a nicer version of these methods based on event handlers). However, this type of asynchrony has very little to do with the interaction between consumer and provider. Whether the client application calls GetLoanQuote or BeginGetLoanQuote / EndGetLoanQuote is completely invisible to the service provider. The client proxy will still open an HTTP connection, send the request, and keep the connection open until the response is received. From an observer point of view, this interaction looks rather RPC-like, i.e. synchronous.

Asynchronous Service Handler

On the provider side things naturally look a bit more synchronous: you need to accept a request and process it. The service can't really buck out before the response is computed. However, many service providers maintain a thread pool so that individual requests can be handled by a pool of worker threads. From the request handler's point of view the invocation of a worker thread is asynchronous -- the handler does not block and wait until the handler completes processing the request. Instead, the handler managers many workers at the same time. This type of processing is commonly implemented in most Service Activators because it provides efficient use of resources and good throughput. But again, this asynchrony is related to the local programming model inside the server process. It has no impact on the client programming model or the conversation protocol between consumer and provider.

Asynchronous Conversation

If we want to achieve an asynchronous interaction model between client and server (for example to avoid holding connection resources for the entire duration of a long-running interaction) we need to look outside of the consumer and provider programming models. We can, for example, choose a message-oriented communications layer such as JMS or MSMQ. Or we can use two separate HTTP connections -- one for the request message and one for the response message. In either case we can use the familiar asynchronous messaging patterns such as Correlation Identifier and Return Address to manage the relationship between the two messages. Using HTTP is still not asynchronous from the viewpoint of a single message, i.e. the sender of a message still has to wait for the receiver to respond to the request to establish a connection and until the data is transmitted. However, it does provide asynchrony from the viewpoint of the overall conversation. No conversation state (see Enemy of the State) is held in the connection between consumer and provider. Instead, the state travels with the message that is sent by the consumer to the provider and back.

Conclusion

Asynchrony is a broad concept and not surprisingly there are many incarnations. All types of asynchrony have their place but are very different. Therefore, it is important to avoid confusion by specifying the context when we use the asynchronous pattern names.

Interestingly the same viewpoints apply to the notion of transactions. A lot of messaging layers provide client-side transactions or provider-side transactions but no conversation transactions. This is a very interesting topic, but it'll have to wait for another rambling...

MORE RAMBLINGS    Subscribe  SUBSCRIBE TO GREGOR'S RAMBLINGS


Gregor is a software architect with Google. He is a frequent speaker on asynchronous messaging and service-oriented architectures and co-authored Enterprise Integration Patterns (Addison-Wesley). His mission is to make integration and distributed system development easier by harvesting common patterns and best practices from many different technologies.
www.eaipatterns.com