Bug Tracker

Opened 8 years ago

Closed 8 years ago

Last modified 6 years ago

#10282 closed bug (wontfix)

.ajax's timeout invalidates all remaining ajax calls delegated to XHR object by browser

Reported by: kon@… Owned by: kon@…
Priority: low Milestone: None
Component: ajax Version: 1.6.3
Keywords: Cc: jaubourg
Blocked by: Blocking:

Description

Background

There is a limit to how many XHR objects can be created by the browser. The browser will reuse the same XHR object to make the rest of the calls - a queue based implementation.

The issue

The issue arises when multiple .ajax() requests are issued and a timeout is set. The start time of the timeout is set from the instant that the call is issued (nonblocking call). The call itself might not be processed though if too many requests go out as the browser creates only so many XHR objects. As soon as one times out, it invalidates the rest of the calls, even though the actual request has not been sent yet.

Suggested Fix

In IE (8+), accessible via window.maxConnectionsPerServer, you are able to find out how many XHR objects you will be able to create at any one time. I am not familiar of any such implementation on any other browser. It is suggested to implement a queue-like approach based on this, or the numbers specified by the browsers. At the least, the documentation should perhaps be updated to reflect how the timeout behaves for asynchronous requests.

Change History (12)

comment:1 Changed 8 years ago by Rick Waldron

Component: unfiledajax
Owner: set to kon@…
Status: newpending

Thanks for taking the time to contribute to the jQuery project! Please provide a complete reduced test case on jsFiddle to help us assess your ticket!

Additionally, be sure to test against the jQuery Edge version to ensure the issue still exists. To get you started, use this boilerplate: http://jsfiddle.net/FrKyN/ Open the link and click to "Fork" (in the top menu) to get started.

comment:2 Changed 8 years ago by Rick Waldron

Priority: undecidedlow

comment:3 Changed 8 years ago by konp

Test Case
Please find the JSFiddle reduced test case here: http://jsfiddle.net/Xjm7g/4/

The test case demonstrates the behavior in Chrome but same behavior is observed in IE9 (not with this test case though, as IE for some reason is ignoring the "delay" argument).

Observe
All AJAX requests are non-blocking and fire off at the same time. Note that some timeout before even being fired (4-5 requests typically) as their "timeout" starts from the moment the .ajax() method is called.

Expected
'timeout' refers to how long a request should live, and should only start counting when the request is fired.

Actual
'timeout' refers to the instant the .ajax() method is called, even if browser does not fire the request due to several existing XHR requests

Note: 6 XHR objects available in chrome when connection is not VPNed.

Last edited 8 years ago by konp (previous) (diff)

comment:4 Changed 8 years ago by jaubourg

Cc: jaubourg added
Keywords: needsdocs added

OK, I was a bit confused when I first read your report: XHR objects actually ARE created, but the request is not issued immediately. You can create as many XHR objects as you want, but only 6 (in the example of Chrome) will be issued concurrently (I suppose it's 6 per domain). Even worse, it may very well be a cross-tab limitation (making it impossible to have more than 6 concurrent requests per domain for the whole collection of tabs actually opened in Chrome).

That being said, it may be possible to inititate the timeout only when the readyState changes to a "requesting" state but is it desirable? When you set the timeout in ajax, you do express you want the request to be complete in, say, 8 seconds top. That the timeout is due to the server hanging or the request not being issued by the client yet is somehow irrelevant. The timeout set in the ajax options is an applicative timeout (it will incidently also work for script tag injection, knowing that this particular technique is even more limited in its number of concurrent request per domain). It will be impossible to ensure any kind of consistency here between different transports.

Furthermore, when I see that many concurrent requests to the same domain at the same time, I'm starting to wonder how the application is architected. You could easily group/multiplex requests client-side and ungroup/demultiplex requests server-side (it may even be possible to create a transport that does just that).

I know it sucks when you're hitting limitations of the browser, but jQuery can only do so much magic before becoming an inconsistent piece of script.

comment:5 Changed 8 years ago by konp

There are no cross-tab limitation, and the limitation is eliminated by using "The CNAME" trick. There is a limit per domain, but that is in the upwards of 30-some requests.

The scenario is that you have a webpage with dynamically generated "webparts" or sections on the page that can be drag-and-dropped at will of the user. there is a common "requester manager" that delegates all of the requests on the page (which is how I have currently implemented the throttling issue). The webparts are themselves stateless (meaning they also are unaware of where they exist, or what exists around them).

The service calls can take up to several seconds to complete, and therefore I cannot set a timeout of say 5 seconds for a request as it will execute immediately and the webpart will fail to load. In VPN'ed scenarios, IE will actually limit the XHR requests to a maximum of 2 (I am unsure of what Chrome and FF do, but I can investigate if necessary).

I totally understand that the timeout set is from the moment that the .ajax call is made, but perhaps it would be beneficial to expand the method with code that actually implements the timeout based on the XHR readystates.

The CNAME trick is to alias different CNAMES to the same location which make browsers treat it as different domains and therefore do not limit the XHR objects.

comment:6 Changed 8 years ago by trac-o-bot

Resolution: invalid
Status: pendingclosed

Because we get so many tickets, we often need to return them to the initial reporter for more information. If that person does not reply within 14 days, the ticket will automatically be closed, and that has happened in this case. If you still are interested in pursuing this issue, feel free to add a comment with the requested information and we will be happy to reopen the ticket if it is still valid. Thanks!

comment:7 Changed 8 years ago by konp

I am the person who initially opened the ticket - just want to verify if anyone actually saw my last reply to the ticket before it was autoclosed by bot.

comment:8 Changed 8 years ago by timmywil

Resolution: invalid
Status: closedreopened

comment:9 Changed 8 years ago by timmywil

Resolution: wontfix
Status: reopenedclosed

Closing as wontfix and leaving needsdocs per jaubourg's last comment. If needed, we can reopen the ticket.

comment:10 Changed 8 years ago by dmethvin

Keywords: needsdocs removed

I've updated the docs. This really seems like a cantfix to me, the browsers don't provide any indication of the number of requests available except for IE. The user can change the value (e.g. about:config network.http.max-connections-per-server in Firefox) so we can't even do some sort of browser-specific check.

comment:11 Changed 6 years ago by joe@…

I would like this reopened. I just ran into a similar problem.

I have a regular poll of XHR requests that occasionally get locked up by the server, ultimately timing out. When that happens, I am unable to send other AJAX requests to the server until enough trigger timeout that the queue clears. Since these later AJAX requests are actually to fix the problem causing the timeout, it's a bit of a lock-down.

I'm finding work-arounds but I hit this bug and wondered if there were a better way around it. Perhaps a way to specify a named queue that would throttle requests so that queue only has one AJAX at a time. Then my polling could be isolated and the control requests could function even after the polling gets jammed.

comment:12 Changed 6 years ago by dmethvin

@joe, we closed the bug wontfix and actually it seems like a cantfix. What's the purpose of reopening the ticket? If you have a solution we've missed then let us know. Otherwise you'll need to throttle requests yourself using the lowest common denominator which is 2 requests for IE6.

Note: See TracTickets for help on using tickets.