Multiple calls to same asynchronous handler block each other.

248 views
Skip to first unread message

Brian McFadden

unread,
Nov 9, 2010, 1:36:27 PM11/9/10
to Tornado Web Server
Hello again,

I addressed this problem in my last e-mail to my previous thread.
Since it's a bit out of the scope of that original subject, and since
nobody responded, I figured that it would be ok to start a new topic.

I noticed that multiple requests to pages on the same asynchronous
handler are handled synchronously with respect to each other... that
is, multiple HTTP requests to a blocking handler must each wait their
turn to receive a response. In a toy example where a handler sleeps
for 5 seconds, 3 requests fired at (nearly) the same time will receive
a response at (around) the 5, 10, and 15 second marks. I performed
this test simply using three browser windows.

The code for this is available via Gist: https://gist.github.com/661743

This does not affect other handlers. Since the handler that I
described is asynchronous, connections to other handlers occur as
expected; there is no waiting.

I noticed it after solving my previous problem, but I checked with
some older code (which used process pools and apply_async) and saw it
there too. I then checked with an example I found at this blog:
http://brianglass.wordpress.com/2009/11/29/asynchronous-shell-commands-with-tornado/
that uses popen and noticed the same problem. As you can see, I
commented, and he found his example to also experience this issue,
though he claims he's pretty sure it used to work. Once again, he can
continually refresh a page while another page's handler blocks for a
few seconds.

This got me curious, and I constructed one last example. Perhaps Brian
Glass and I both constructed our examples incorrectly. I decided to
fill out the example demonstrating the asynchronous HTTP client
straight out of the Tornado documentation:
http://www.tornadoweb.org/documentation#non-blocking-asynchronous-requests
This takes the manual callback adding out the picture. I can't imagine
something we both did that would make requests to the same handler
block, but letting the library handle that aspect would solidify my
belief that there was a problem.

Here's that code in a complete Tornado program with print statements:
https://gist.github.com/669536

Indeed, I experience the same problem using that example. There is
less time, but if you quickly use multiple browser windows and pay
attention to stdout, you'll see that the get function is not entered
until the last request finish()es.

I can't imagine this is by design. Am I experiencing a bug? I'm on
Ubuntu 10.04, using the package version of Python (2.6.5) and Tornado
1.1.

Ben Darnell

unread,
Nov 9, 2010, 2:01:09 PM11/9/10
to python-...@googlegroups.com
I think it's the browser serializing the requests. I can't reproduce
any problems when making the requests with curl, but with two chrome
tabs the second request doesn't get sent until the first one is
finished.

-Ben

Brian McFadden

unread,
Nov 9, 2010, 2:12:46 PM11/9/10
to Tornado Web Server
Brilliant. I had never considered that possibility. I, too, see normal
operation using cURL. Thanks for the response, Ben. I'll definitely be
keeping this one in mind for future tests.

-Brian

On Nov 9, 2:01 pm, Ben Darnell <b...@bendarnell.com> wrote:
> I think it's the browser serializing the requests.  I can't reproduce
> any problems when making the requests with curl, but with two chrome
> tabs the second request doesn't get sent until the first one is
> finished.
>
> -Ben
>
> On Tue, Nov 9, 2010 at 10:36 AM, Brian McFadden <brimcfad...@gmail.com> wrote:
> > Hello again,
>
> > I addressed this problem in my last e-mail to my previous thread.
> > Since it's a bit out of the scope of that original subject, and since
> > nobody responded, I figured that it would be ok to start a new topic.
>
> > I noticed that multiple requests to pages on the same asynchronous
> > handler are handled synchronously with respect to each other... that
> > is, multiple HTTP requests to a blocking handler must each wait their
> > turn to receive a response. In a toy example where a handler sleeps
> > for 5 seconds, 3 requests fired at (nearly) the same time will receive
> > a response at (around) the 5, 10, and 15 second marks. I performed
> > this test simply using three browser windows.
>
> > The code for this is available via Gist:https://gist.github.com/661743
>
> > This does not affect other handlers. Since the handler that I
> > described is asynchronous, connections to other handlers occur as
> > expected; there is no waiting.
>
> > I noticed it after solving my previous problem, but I checked with
> > some older code (which used process pools and apply_async) and saw it
> > there too. I then checked with an example I found at this blog:
> >http://brianglass.wordpress.com/2009/11/29/asynchronous-shell-command...
> > that uses popen and noticed the same problem. As you can see, I
> > commented, and he found his example to also experience this issue,
> > though he claims he's pretty sure it used to work. Once again, he can
> > continually refresh a page while another page's handler blocks for a
> > few seconds.
>
> > This got me curious, and I constructed one last example. Perhaps Brian
> > Glass and I both constructed our examples incorrectly. I decided to
> > fill out the example demonstrating the asynchronous HTTP client
> > straight out of the Tornado documentation:
> >http://www.tornadoweb.org/documentation#non-blocking-asynchronous-req...

Christopher Becker

unread,
Nov 9, 2010, 3:52:15 PM11/9/10
to python-...@googlegroups.com
A great solution is "roaming domains" as we call it in our application. Set up your domain's dns to use a wildcard - say you were making connections to blah.company.com, add a wildcard for *.blah.company.com. On page load, do your ajax/long poll requests against a randomly generated subdomain, i.e. [random_string].blah.company.com

This tricks some browsers (chrome in particular) into allowing more connections because it appears to be a "different" domain and chrome limits the number of simultaneous transfers to any single domain. There is a very minor performance hit on page load, as clients must do a DNS lookup for a new domain on every page load. For us the benefits (no deadlocked chrome as soon as 2-3 tabs are open) outweighed this minor drawback, but I also think it would be possible to recycle a "pool" of different subdomains to benefit DNS cache/performance.

Best of luck!
-Chris

Reply all
Reply to author
Forward
0 new messages