Keeping track of state in asynchronous callbacks


Published on

There’s a lot of confusion about how asynchronous communication works in RIA’s
such as Silverlight, GWT and Javascript. When I start talking about the problems of
concurrency control, many people tell me that there aren’t any concurrency problems
since everything runs in a single thread. [1]
It’s important to understand the basics of what is going on when you’re writing
asynchronous code, so I’ve put together a simple example to show how execution
works in RIA’s and how race conditions are possible. This example applies to
Javascript, Silverlight, GWT and Flex, as well as a number of other environments
based on Javascript. This example doesn’t represent best practices, but rather what
can happen when you’re not using a proactive strategy that eliminates concurrency problems

Published in: Technology, Business
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Keeping track of state in asynchronous callbacks

  1. 1. Generation 5 » Keeping Track Of State In Asynchronous Callbacks  Subscribe to our RSS Feed | About Us Keeping Track Of State In Asynchronous Callbacks When you’re writing applications that use asynchronous callbacks (i.e. Silverlight, AJAX, or GWT) you’ll eventually run into the problem of keeping track of the context that a request is being done in. This isn’t a problem in synchronous programming, because local variables continue to exist after one function calls another function synchronously: int AddToCount(int amount,string countId) int countValue=GetCount(countId); return countValue+amount; } { This doesn’t work if the GetCount function is asynchronous, where we need to write something like int AddToCountBegin(int amount,string countId,CountCallback outerCallback) { GetCountBegin(countId,AddToCountCallback); } void AddToCountCallback(int countValue) { ... some code to get the values of amount and outerCallback ... outerCallback(countValue+amount); } Several things change in this example: (i) the AddToCount function gets broken up into two functions: one that does the work before the GetCount invocation, and one that does the work after GetCount completes. (ii) We can’t return a meaningful value from AddToCountCallback, so it needs to ‘return’ a value via a specified callback function. (iii) Finally, the values of outerCallback and amount aren’t automatically shared between the functions, so we need to make sure that they are carried over somehow. There are three ways of passing context from a function that calls and asynchronous function to the callback function: 1. As an argument to the callback function 2. As an instance variable of the class of which the callback function is a class 3. Via a closure Let’s talk about these alternatives: 1. Argument to the Callback Function In this case, a context object is passed to the asynchronous function, which passes the context object to the callback. The advantage here is that there aren’t any constraints on how the callback function is implemented, other than by accepting the context object as a callback. In particular, the callback function can be static. A major disadvantage is that the asynchronous function has to support this: it has to accept a state object which it later passes to the callback function. The implementation of HttpWebRequest.BeginGetResponse(AsyncCallback a,Object state) in the Silverlight libraries is a nice example. If you wish to pass a context object to the AsyncCallback, you can pass it in the second parameter, state. Your callback function will implement the AsyncCallback delegate, and will get something that implements IAsyncResult as a parameter. The state that you passed into BeginGetResponse will come back in the IAsyncResult.AsyncState property. For example: class MyHttpContext { public HttpWebRequest Request; public SomeObject FirstContextParameter; public AnotherObject AnotherContextParameter; } protected void myHttpCallback(IAsyncResult abstractResult) { MyHttpContext context = (MyHttpContext) abstractResult.AsyncState; HttpWebResponse Response=(HttpWebResponse) context.Request.EndGetResponse(abstractResult); }[1/12/2014 9:30:30 PM] Search for: Search Archives June 2012 (1) August 2010 (1) May 2010 (1) June 2009 (2) April 2009 (1) March 2009 (1) February 2009 (3) January 2009 (3) November 2008 (1) August 2008 (2) July 2008 (5) June 2008 (5) May 2008 (2) April 2008 (6) March 2008 (8) June 2006 (1) February 2006 (1) Categories AJAX (2) Asynchronous Communications (16) Biology (1) Books (1) Design (1) Distributed (1) Exceptions (2) Functional Programming (1) GIS (1) Ithaca (1) Japan (1) Math (1) Media (3) Nature (1) Semantic Web (3) Tools (28) CRUD (1) Dot Net (17) Freebase (2) GWT (9) Java (7) Linq (2) PHP (6) Server Frameworks (1) Silverlight (12) SQL (5) Uncategorized (1) Web (2) Analytics (1)
  2. 2. Generation 5 » Keeping Track Of State In Asynchronous Callbacks public doHttpRequest(...) { ... MyHttpContext context=new MyHttpContext(); context.Request=Request; context.FirstContextParameter = ... some value ...; context.AnotherContextParameter = .. another value ...; Request.BeginGetResponse(); Request.Callback(myHttpCallback,context); } Note that, in this API, the Request object needs to be available in myHttpCallback because myHttpCallbacks get the response by calling the HttpWebResponse.EndGetResponse() method. We could simply pass the Request object in the state parameter, but we’re passing an object we defined, myHttpCallback, because we’d like to carry additional state into myHttpCallback. Note that the corresponding method for doing XMLHttpRequests in GWT, the use of a RequestBuilder object doesn’t allow using method (1) to pass context information — there is no state parameter. in GWT you need to use method (2) or (3) to pass context at the RequestBuilder or GWT RPC level. You’re free, of course, to use method (1) when you’re chaining asynchronous callbacks: however, method (2) is more natural in Java where, instead of a delegate, you need to pass an object reference to designate a callback function. 2. Instance Variable Of The Callback Function’s Class Functions (or Methods) are always attached to a class in C# and Java: thus, the state of a callback function can be kept in either static or instance variables of the associated class. I don’t advise using static variables for this, because it’s possible for more than one asynchronous request to be flight at a time: if two request store state in the same variables, you’ll introduce race conditions that will cause a world of pain. (see how race conditions arise in asynchronous communications.) Method 2 is particularly effective when both the calling and the callback functions are methods of the same class. Using objects whose lifecycle is linked to a single asynchronous request is an effective way to avoid conflicts between requests (see the asynchronous command pattern and asynchronous functions.) Here’s an example, lifted from the asynchronous functions article: public class HttpGet : IAsyncFunction<String> { private Uri Path; private CallbackFunction<String> OuterCallback; private HttpWebRequest Request; public HttpGet(Uri path) { Path = path; } public void Execute(CallbackFunction<String> outerCallback) { OuterCallback = outerCallback; try { Request = (HttpWebRequest)WebRequest.Create(Path); Request.Method = "GET"; Request.BeginGetRequestStream(InnerCallback,null); } catch (Exception ex) { OuterCallback(CallbackReturnValue<String>.CreateError(ex)); } } public void InnerCallback(IAsyncResult result) { try { HttpWebResponse response = (HttpWebResponse) Request.EndGetResponse(result); TextReader reader = new StreamReader(response.GetResponseStream()); OuterCallback(CallbackReturnValue<String>.CreateOk(reader.ReadToEnd())); } catch(Exception ex) { OuterCallback(CallbackReturnValue<String>.CreateError(ex)); } } } Note that two pieces of context are being passed into the callback function: an HttpWebRequest object named Request (necessary to get the response) and a CallbackFunction<String> delegate named OuterCallback that receives the return value of the asynchronous function. Unlike Method 1, Method 2 makes it possible to keep an unlimited number of context variables that are unique to a particular case in a manner that is both typesafe and[1/12/2014 9:30:30 PM]
  3. 3. Generation 5 » Keeping Track Of State In Asynchronous Callbacks oblivious to the function being called — you don’t need to cast an Object to something more specific, and you don’t need to create a new class to hold multiple variables that you’d like to pass into the callback function. Method 2 comes into it’s own when it’s used together with polymorphism, inheritance and initialization patterns such as the factory pattern: if the work done by the requesting and callback methods can be divided into smaller methods, a hierarchy of asynchronous functions or commands can reuse code efficiently. 3. Closures In both C# and Java, it’s possible for a method defined inside a method to have access to variables in the enclosing method. In C# this is a matter of creating an anonymous delegate, while in Java it’s necessary to create an anonymous class. Using closures results in the shortest code, if not the most understandable code. In some cases, execution proceeds in a straight downward line through the code — much like a synchronous version of the code. However, people sometimes get confused the indentation, and, more seriously, parameters after the closure definition and code that runs immediately after the request is fired end up in an awkward place (after the definition of the callback function.) public class HttpGet : IAsyncFunction<String> { private Uri Path; public HttpGet(Uri path) { Path = path; } public void Execute(CallbackFunction<String> outerCallback) { OuterCallback = outerCallback; try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Path); Request.Method = "GET"; Request.BeginGetRequestStream(delegate(IAsyncResult result) { try { response = request.EndGetResponse(result); TextReader reader = new StreamReader(response.GetResponseStream()); outerCallback(CallbackReturnValue<String>.CreateOk(reader.ReadToEnd())); } catch(Exception ex) { outerCallback(CallbackReturnValue<String>.CreateError(ex)); } },null); // <--- note parameter value after delegate definition } catch (Exception ex) { outerCallback(CallbackReturnValue<String>.CreateError(ex)); } } } The details are different in C# and Java: anonymous classes in Java can access local, static and instance variables from the enclosing context that are declared final — this makes it impossible for variables to be stomped on while an asynchronous request is in flight. C# closures, on the other hand, can access only local variables: most of the time this prevents asynchronous requests from interfering with one another, unless a single method fires multiple asynchronous requests, in which case counter-intuitive things can happen. Conclusion In addition to receiving return value(s), callback functions need to know something about the context they run in: to write reliable applications, you need to be conscious of where this information is; better yet, a strategy for where you’re going to put it. Closures, created with anonymous delegates (C#) or classes (Java) produce the shortest code, but not necessarily the clearest. Passing context in an argument to the callback function requires the cooperation of the called function, but it makes few demands on the calling and callback functions: the calling and callback functions can both be static. When a single object contains both calling and callback functions, context can be shared in a straightforward and typesafe manner; and when the calling and callback functions can be broken into smaller functions, opportunities for efficient code reuse abound.[1/12/2014 9:30:30 PM]
  4. 4. Generation 5 » Keeping Track Of State In Asynchronous Callbacks Paul Houle on June 2nd 2008 in Asynchronous Communications, Dot Net, GWT, Java, Silverlight Comments (6) Comments (6) Login Sort by: Date Rating Last Activity Thomas Hansen · 292 weeks ago +1 Or you could use an Ajax Framework that queues up the requests which is the only sane thing to do when you have a server/client solution and waits for the previous one to finish before creating a new one ;) (Hint; follow my link) Nice blog though, and VERY important to be aware of, though probably less than 1% of ASP.NET AJAX developers are... :) Reply admin · 292 weeks ago 0 @Thomas, your solution is a correct way to use AJAX and makes a lot of sense. There is one case where it does make sense to generate concurrent requests, and that's when information from several requests is going to be combined. Running requests in parallel can greatly reduce the effects of latency -- in many cases this can make a large difference in performance (much more than two.) I think most people doing AJAX in Javascript can get away with being ignorant about concurrency problems because they're bolting simple behaviors onto an HTML page: when something does go wrong, the situation is usually recoverable. I know that I programmed a little AJAX here and there for years and never experienced concurrency problems -- then I built a GWT app! People working with tools like Silverlight, GWT and Flex (as well as a few brave Javascript Ninjas) are building larger applications that are going to have more problems. It's time to spread the word about the problems and the solutions! Reply Thomas Hansen · 292 weeks ago 0 @admin Yes I totally agree, in fact I by "chance" stumbled into the problem when adding up a timer onto my page and then frenetically clicked a button at the same time and by accident discovered that sometimes the ViewState went completely *bananas* and the page became in an "undefined state"... Then I spent more than a WEEK in fact re-creating our core to give support for sequential requests... I think that yes you are right, there might exist some extreme scenarios where it makes sense to have more than one running at the same time, though if they're both running towards the same server, you will get OTHER problems (2 HTTP connections per IP constraint in most browsers) So I think probably if you are going to use them you would normally have them first of all run towards different IPs (servers) then also in addition it would be *WISE* to make sure they're not updating the same parts of the UI... Though for us (Gaia Ajax Widgets) this is completely abstract and would never happen unless people completely mis-used our framework in ways it was never intended to be used for... On the server creating more than one request towards OTHER servers (WebServices and so on) asynchronously though is a totally different story... .t Reply admin · 292 weeks ago 0 Well, in a perfect world, we'd design the client-server protocol so that all the information that the client needs to handle a UI event comes in one big batch... Then you don't need to worry about choreography, error handling and all those hairy issues. See this article. In the real world we need to talk to server apps that we don't control... So we have to deal with those issues.[1/12/2014 9:30:30 PM]
  5. 5. Generation 5 » Keeping Track Of State In Asynchronous Callbacks Reply Generation 5 » Getting back to the UI Thread in Silverlight 2 Beta 2 [...] but what if you want to pass some parameters to the function that updates the UI.  The usual three choices for passing state in asynchronous applications apply,  but it’s particularly easy and fun to use a closure [...] Generation 5 » Converting A Synchronous Program Into An Asynchronous Program [...] it’s useful for f() to correspond to an object, of which the fN() functions are methods. [1] [2] [...] Post a new comment Enter text right here! Comment as a Guest, or login: Name Email Displayed next to your comments. Subscribe to Website (optional) Not displayed publicly. If you have a website, link to it here. None None Submit Comment Copyright © 2013 Generation 5. WordPress Theme design.[1/12/2014 9:30:30 PM]