Skip to content

Commit

Permalink
Merge pull request dotnet#1164 from mconnew/HttpClientTimerPerfFix
Browse files Browse the repository at this point in the history
Prevent HttpClient from setting a timer on internal cancellation token
  • Loading branch information
mconnew committed May 18, 2016
2 parents 79967bd + 57f13eb commit f938449
Showing 1 changed file with 12 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,11 @@ internal HttpClient GetHttpClient(EndpointAddress to, NetworkCredential credenti

httpClient = new HttpClient(clientHandler);

// We provide our own CancellationToken for each request. Setting HttpClient.Timeout to -1
// prevents a call to CancellationToken.CancelAfter that HttpClient does internally which
// causes TimerQueue contention at high load.
httpClient.Timeout = Timeout.InfiniteTimeSpan;

_httpClientCache.Add(connectionGroupName, httpClient);
}
}
Expand Down Expand Up @@ -937,13 +942,14 @@ public async Task SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
catch { /* ignored */ }

bool success = false;
var cancelTokenTask = _timeoutHelper.GetCancellationTokenAsync();
var timeoutToken = await _timeoutHelper.GetCancellationTokenAsync();

try
{
var timeoutToken = await cancelTokenTask;
timeoutToken.Register(s_cancelCts, _httpSendCts);
_httpResponseMessage = await _httpClient.SendAsync(_httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, _httpSendCts.Token);
using (timeoutToken.Register(s_cancelCts, _httpSendCts))
{
_httpResponseMessage = await _httpClient.SendAsync(_httpRequestMessage, HttpCompletionOption.ResponseHeadersRead, _httpSendCts.Token);
}

// As we have the response message and no exceptions have been thrown, the request message has completed it's job.
// Calling Dispose() on the request message to free up resources in HttpContent, but keeping the object around
Expand All @@ -958,14 +964,14 @@ public async Task SendRequestAsync(Message message, TimeoutHelper timeoutHelper)
}
catch (OperationCanceledException)
{
if (cancelTokenTask.Result.IsCancellationRequested)
if (timeoutToken.IsCancellationRequested)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.Format(
SR.HttpRequestTimedOut, httpRequestMessage.RequestUri, _timeoutHelper.OriginalTimeout)));
}
else
{
// Cancellation came from somewhere other than timeoutCts and needs to be handled differently.
// Cancellation came from somewhere other than timeoutToken and needs to be handled differently.
throw;
}
}
Expand Down

0 comments on commit f938449

Please sign in to comment.