Saturday, February 25, 2012

A little Async problem

Hello again.  I am going to attempt (yet again) to start a blog and keep updating it.  I have found in the past that I quickly run out of topics if I narrow the focus too much.  I also don’t want to blog about what I had for lunch each day.  This is my latest attempt at finding the balance.  C# is what I code in, so that is what I will write about.  Thanks for watching!

Last night I solved a problem that had been bugging me for a week or more.  It has to do with this code:

 

 public void GetResultsAsync<T>(RestRequest request, 
Action<T> callback)
{
var restCallback = new RestCallback(
(req, resp, obj) =>
{
callback(GetResults<T>(req));
}
);
_oauth.BeginRequest(request, restCallback);

}

public T GetResults<T>(RestRequest request)
{
var response = Request(request);
var result = GetResponse<T>(
response.ContentStream);

if (result.Status != "ok")
{
throw new GeekListException(
result.Status, result.Error);
}

return result.Data;
}
See the problem?  If you do, you are much better at this than I am.  I am just getting into Asynchronous patterns as part of the Windows Phone coding that I am doing in my spare time, so some of this is new to me.  I still don’t fully grok binding and template usage on the phone with async data sources, but I am getting there.


Want a hint?  My unit tests are failing for any async method that creates a new item.  Curious isn’t it?  All of the retrieval tests work fine, just not the creates.  Take a moment to look back at the code if you want, I will wait. 


How do you debug something like this?  Fiddler is my tool of choice, and I quickly discovered that I was making two calls to the web site for each async call:


2012-02-19_2242


2012-02-19_2242_001


and the second one was failing because it was trying to insert duplicate data.  Have you figured it out yet?  Take another look back at the code.  Isn’t it obvious?  Well, it wasn’t to me.  I spent a couple of days banging my head against hard vertical objects like walls, doors, trees, etc. 


I decided that perhaps the OAuth library that I was using was mis-behaving (blame someone else) so I grabbed a fork from GitHub and started tracing code. 



This won’t take long…I am sure there is just a misplaced…wait, this looks good.  Gack, this is complex!  Oh, that’s right, that is why I am using a library rather than rolling my own. 


I thought that it must be some type of re-try issue, so I updated the GetResultsAsync method to decorate the request with all sorts of time and retry related stuff:

public void GetResultsAsync<T>(   
Action<T> callback,
RestRequest request)
{
var restCallback = new RestCallback(
(req, resp, obj) => callback(
GetResults<T>(resp)));
request.Timeout =
new TimeSpan(0, 0, 5);
request.RetryPolicy =
new Hammock.Retries.RetryPolicy();
request.RetryPolicy.RetryCount = 0;
_oauth.BeginRequest(request,
restCallback);
}

but no amount of request tweaking would keep the second call from showing up in Fiddler.


Finally, in desperation, I even opened a question on StackOverflow (http://stackoverflow.com/questions/9372760/hammock-async-calls-appear-to-be-duplicated, yes, I deleted it once I found my problem), which as a long time lurker, was admitting defeat in an epic way.  I showed code, the screen shots from above, tagged it with appropriate tags, and waited.


And then no-one swooped in to save the day.  Ouch, only 5 views of the question in as many days and no comments or answers?  *sigh* 



Perhaps if I build a test project and provide a more complete solution?  Is there an OAuth service that I can test against?  http://term.ie/oauth/example/ looks good.  Let me just make a new project and do some basic authentication…


And then, while building an isolated test project (I use WinForms for these because I like to push buttons and see stuff happen) I found my error.  Wow, was it


Ok, last chance, have you found my problem?  I am about to show the refactored code, and I don’t want to ruin it for anyone playing the home game. 


Ok, you were warned, here it is:




public void GetResultsAsync<T>(Action<T> callback, RestRequest request)
{
var restCallback = new RestCallback(
(req, resp, obj) => callback(GetResults<T>(resp)));
_oauth.BeginRequest(request, restCallback);
}

public T GetResults<T>(RestRequest request)
{
var response = Request(request);

return GetResults<T>(response);
}


public T GetResults<T>(RestResponse response)
{
var result = GetResponse<T>(response.ContentStream);

if (result.Status != "ok")
{
throw new GeekListException(result.Status, result.Error);
}

return result.Data;
}

There, see it?  It is subtle until it smacks you in the face.  I was doing a synchronous call in the middle of my asynchronous handler.  Yes I was, look again.  That is the whole reason I had listed the GetResults method to begin with, show dependencies and all.  *sigh* 


I haven’t thought through all of this fully yet, so I am sure that the above code breaks a ton of pattern rules, and has a code smell foul enough to clear a room full of PHP coders, but it works.  I will try and get back to this if I refactor it, but this is good enough for now.


Thanks for listening!

No comments:

Post a Comment