4

i'm facing whit httpclient and timeout configuration. After doing a lot of googling i got on these conclussions:

  • Http client timeout is fine only once i connect to an avaiable host/server.
  • If Host is unavaiable or server is down, HttpClient.Timeout does not matter and i'm getting a TaskCancelledException wrapping SocketException (connection refused) after about 80seconds.

I learn httpClient timeout works only after the server recieves the request, so, if host/server is down, i get so longs timeouts related to sockets.

I need to configure a more "wide" timeout for my httpClient getAsync, postAsync... requests, and stop the operation at the specified amount of time regarless the server is avaiable or not.

I cant figure out what i could do to control timeour effectively, that stackoverflow thread (link), suggest task calcellation approach on this manner:

var timeout = Task.Delay(10000); // 10 seconds timeout
var request = httpClient.GetAsync("http://www.google.com");

await Task.WhenAny(timeout, request); // wait for either timeout or the request

if (timeout.IsCompleted) // if the timeout ended first, then handle it
{
    // handle timeout
}

// otherwise continue processing the request result
var response = await request;

While that might work i will lost the socket exception and offers poor control. Because, in short, what i'm trying to do is find a way to set a timeout for resolution/connection to the server (about 2 seconds), and higher timeout for waiting the response once connection is stablished to the server.

It makes senses for me because my web server is accesed througt local network, so, 2 seconds is more than enought to get the conclusion of "server unavaiable", but once the server start processing the response i need a bigger timeout for waiting response.

Thanks in advance.

Ashish Rathi
  • 1,418
  • 2
  • 13
  • 26
Fran CD
  • 167
  • 3
  • 11

3 Answers3

1

that stackoverflow thread... , suggest task calcellation approach

The linked question approach is the right way to go.

Basically, the problem is in that connection timeout is managed by OS settings, and you can't set it directly in code.

While that might work i will lost the socket exception and offers poor control

There's no problem with catching and logging socket exception (or any other exception). Just set appropriate task cancellation for the "main" task:

// task is returned from async method performing payload, e.g. httpClient.GetAsync
task.ContinueWith(
    t =>
    {
        var exception = t.Exception;

        // do what you want here
    },
    TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
Dennis
  • 37,026
  • 10
  • 82
  • 150
  • I will give it a try, but, in advance, i thinks is as nothing to do with my goal that is, as described in question: "...in short, what i'm trying to do is find a way to set a timeout for resolution/connection to the server (about 2 seconds), and higher timeout for waiting the response once connection is stablished to the server." – Fran CD Nov 14 '19 at 08:39
  • @FranCD: Yes, you can't set it. So, the only way is to "forget" about long-running connection attempt. – Dennis Nov 14 '19 at 08:42
  • Really annoying, it should exist a way to control different timeouts properly, since 2 seconds can be enought to determine is server is avaiable or not, but it could be too few for awaiting some request results. I post an answer with a workaround idea (i'll try it today) ¿What do you think about that idea? – Fran CD Nov 14 '19 at 10:04
0

I'm thinking on this workaround approach:

Start two parallel http requests, one of them is a dummy get request (the server directy responses OK), and i will wait this task 2 seconds with the reccomended approach you can see in the question. The other resquest is the "real request"... If first request is not completed in two seconds, i cancel the second request too, but if first request ends ok, then the server is working ok and i rely on httpClient.Timeout for the second request.

Yes, is an overhead to the server because each request becomes two requests, but my server is local network with no more than 5-10 clients doing only 1-2 requests per minute, so, i will consider this approach. Or maybe it sucks to a bad idea... What do you think?

Fran CD
  • 167
  • 3
  • 11
-1

Since GetAsync return Task Then you can use Task.Wait Method

ex:

var readTask = httpClient.GetAsync("http://www.google.com");

if (readTask.Wait(2 * 1000))
{
    // Return Result if exec dosn't take more than 2 sec
    // return await readTask;
    return readTask.Result;
}
else
{
    // Fail to complete exec in 2 sec
    return string.Empty;
}
CorrM
  • 498
  • 6
  • 18
  • 1
    I will give it a try, but, in advance, i thinks is as nothing to do with my goal that is, as described in question: "...in short, what i'm trying to do is find a way to set a timeout for resolution/connection to the server (about 2 seconds), and higher timeout for waiting the response once connection is stablished to the server." – Fran CD Nov 14 '19 at 08:38
  • 1
    @FranCD: don't wait async tasks this way. This code 1) blocks calling thread; 2) leads to deadlocks. Do it in async manner, like in the question you linked. – Dennis Nov 14 '19 at 08:44
  • i just here to explain that there wait method, and i refer to MSDN link to know who it's work. – CorrM Nov 14 '19 at 10:41