views:

732

answers:

3

Hi all … I’m trying to issue web requests asynchronously. I have my code working fine except for one thing: There doesn’t seem to be a built-in way to specify a timeout on BeginGetResponse. The MSDN example clearly show a working example but the downside to it is they all end up with a

SomeObject.WaitOne()

Which again clearly states is blocks the thread. I will be in a high load environment and can’t have blocking but I also need to timeout a request if it takes more than 2 seconds. Short of creating and managing a separate thread pool, is there something already present in the framework that can help me?

Starting examples: http://msdn.microsoft.com/en-us/library/ms227433(VS.100).aspx http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse.aspx

What I would like is a way for the async callback on BeginGetResponse() to be invoked after my timeout parameter expires, with some indication that a timeout occurred.

The seemingly obvious TimeOut parameter is not honored on async calls. The ReadWriteTimeout parameter doesn't come into play until the response returns. A non-proprietary solution would be preferable.

EDIT:

Here's what I came up with: after calling BeginGetResponse I create a Timer with my duration and that's the end of the "begin" phase of processing. Now either the request will complete and my "end" phase will be called OR the timeout period will expire.

To detect the race and have a single winner I call increment a "completed" counter in a thread-safe manner. If "timeout" is the 1st event to come back, I abort the request and stop the timer. In this situation, when "end" is called the EndGetResponse throws an error. If the "end" phase happens first, it increments the counter and the "timeout" foregoes aborting the request.

This seems to work like I want while also providing a configurable timeout. The downside is the extra timer object and the callbacks which I make no effort to avoid. I see 1-3 threads processing various portions (begin, timed out, end) so it seems like this working. And I don't have any "wait" calls.

Have I missed too much sleep or have I found a way to service my requests without blocking?

    this.Request.BeginGetResponse(GotResponse, this.Request);
    this.timer = new Timer(Timedout, this, TimeOutDuration, Timeout.Infinite);

    private void Timedout(object state)
    {
        if (Interlocked.Increment(ref completed) == 1)
        {
            this.Request.Abort();
        }
        this.timer.Change(Timeout.Infinite, Timeout.Infinite);
        this.timer.Dispose();
    }


    private void GotRecentSearches(IAsyncResult result)
    {
        Interlocked.Increment(ref completed);
A: 

You can to use a BackgroundWorker to run your HttpWebRequest into a separated thread, so your main thread still alive. So, this background thread will be blocked, but first one don't.

In this context, you can to use a ManualResetEvent.WaitOne() just like in that sample: HttpWebRequest.BeginGetResponse() method.

Rubens Farias
as noted in my question, WaitOne blocks. I need a non-blocking solution.
No Refunds No Returns
Yes, it blocks current thread. That's why I suggest to run it inside a `BackgroundThread`
Rubens Farias
It's still consuming a ThreadPool thread if you do that. see my latest edit.
No Refunds No Returns
A: 

What kind of an application is this? Is this a service proces/ web application/console app?

How are you creating your work load (i.e requests)? If you have a queue of work that needs to be done, you can start off 'N' number of async requests (with the framework for timeouts that you have built) and then, once each request completes (either with timeout or success) you can grab the next request from the queue.

This will thus become a Producer/consumer pattern.

So, if you configure your application to have a maximum of "N' requests outstanding, you can maintain a pool of 'N' timers that you reuse (without disposing) between the requests.

Or, alternately, you can use ThreadPool.SetTimerQueueTimer() to manage your timers. The threadpool will manage the timers for you and reuse the timer between requests.

Hope this helps.

feroze
This is a top-10 web site and the logic runs on every page at a rate exceeding 9K rps. Blocking anywhere is not an option.
No Refunds No Returns
If I understand this correctly, you are issuing one (or more) async HTTPWebRequests for each request that is received by the ASPX page?If so, is there any async pattern in ASPX that you can leverage? If there is, you can kick off the async webrequest, and have it's completion trigger the completion of the page. If it times out, you can also trigger the page completion with an error code or something else. That way you wont be holding a threadpool thread.
feroze
A: 

Seems like my original approach is the best thing available.

No Refunds No Returns