C# httpClient (блок для асинхронного вызова) тупик
Текущая ситуация
Есть клиент, который выполняет запрос get от HttpClient.GetAsync. К сожалению, по какой-то причине нам нужно заблокировать эти звонки.
Для этого этот класс Asynchelper используется для того, чтобы избежать взаимоблокировок с переключением контекста (вместо того, чтобы просто использовать.Result)
public static class AsyncHelper
{
private static readonly TaskFactory _myTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static void RunSync(Func<Task> func)
{
AsyncHelper._myTaskFactory
.StartNew<Task>(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
Тогда фактический вызов выглядит так:
AsyncHelper.RunSync(Async Function() Await _httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead))
проблема
Во время стресс-теста с использованием Netlimiter для снижения скорости сети мы столкнулись с проблемой с запросами, которые не были завершены. Например, когда я отключаю сетевое соединение (в NetLimiter), такой запрос навсегда останется на стороне клиента. Он будет оставаться в вызове AsyncHelper.RunSync до тех пор, пока не попадет в httpClient.Timeout.
Не должно ли быть исключение, которое завершит этот вызов при потере соединения? Я что-то пропустил?
1 ответ
Дело в том, что HTTP-соединения обычно проходят через TCP-соединение. Поэтому, когда вы принудительно завершаете TCP-соединение, не имея возможности отправлять свои пакеты "Я закончил" (или FIN), другой конец соединения по-прежнему рад ждать дополнительных данных, по крайней мере, до некоторого определенного времени ожидания. который можно настроить сверху в операциях запроса сокета.
Один из способов справиться с этим - установить TCP Keep-Alive для сокетов. Обратите внимание, что это сильно отличается от HTTP Keep-Alive. Другой вариант, как уже кажется, использовать достаточно хороший тайм - аут.