Asp.net Core Middleware, который отменяет запрос, если долго - PullRequest
0 голосов
/ 03 октября 2018

Мне нужно промежуточное программное обеспечение для отмены запроса, если мой API занимает более х времени.Все мои вызовы API являются асинхронными и могут быть отменены:

public async Task<IActionResult> Get(CancellationToken token) {  }

... 

public async Task InvokeAsync(HttpContext context)
{
    //....
    int customDurationMilis = 1000; //1second

    cancellTimer = new Timer(CancellRequestCallBack, context, customDurationMilis, Timeout.Infinite);
    //...

    await _next(context);
}

private void CancellRequestCallBack(HttpContext context)
{
    //log...
    //Aborts the connection underlying this request.
    context.Abort();
}

представьте, что у меня есть метод действия API, занимающий 2 секунды, таймер вызовет CancellRequestCallBack, который выполняет прерывание соединения.Хорошая идея иметь Таймер?или должен пойти с другим подходом?Как вернуть пользовательский код ошибки вместо context.Abort () и отменить текущий вызов API?некоторые идеи будут очень признательны.спасибо

ОБНОВЛЕНИЕ, пытаясь сделать это с этим:

public async Task InvokeAsync(HttpContext context)
{
    var task = _next(context);

    if (await Task.WhenAny(task, Task.Delay(1000)) != task)
    {
        throw new MyCustomException("timeout!");
    }
}

по крайней мере с этим я ловлю исключение в errorhandlermiddleware, возвращающем код состояния 500. Но я не получаю его в Почтальоне,Вместо этого я получаю сообщение «Не удалось получить ответ». Я предполагаю, что поток с запросом все еще будет работать.

Ответы [ 3 ]

0 голосов
/ 05 октября 2018

Это на самом деле довольно сложно реализовать по нескольким причинам:

  • Отмена является кооперативной.Это означает, что вам нужно все, что вы ожидаете (транзитивно) для соблюдения токена.
  • Быть асинхронным означает, что нет потока для прерывания.Вы можете прервать все TCP-соединение, но если никто не слушает токен и никто не читает тело, это ничего не изменит с работающим кодом сервера.
  • Использование Task.WhenAny не является хорошим решениемпотому что вы могли бы в конечном итоге использовать HttpContext параллельно.Код, который вы «отменили», может быть готов написать правильный ответ, в то время как ваше промежуточное ПО пытается написать ответ на тайм-аут.Даже если вы выбросите исключение, это опасно, потому что есть другой работающий код, который может касаться HttpContext параллельно.

Вы можете рисковать, но могут быть тонкие условия гонки, которые могут привести к непредсказуемым последствиям.

Если вы соблюдаете токены отмены, вы можете просто отменитьтокен и ждать следующего, чтобы раскрутиться.Когда это произойдет, вы сможете увидеть, начался ли ответ, прежде чем писать в него, и вернуть 408 (время ожидания истекло).

0 голосов
/ 08 октября 2018

придумал решение относительно токенов.Идея состоит в том, чтобы создать новый токен и определить тайм-аут для него.Но дополнительно необходимо будет связать оригинальный токен с новым с помощью CreateLinkedTokenSource.

public async Task InvokeAsync(HttpContext context)
{
    using (var timoutTS = CancellationTokenSource.CreateLinkedTokenSource(context.RequestAborted))
    {
        timoutTS.CancelAfter(200);
        context.RequestAborted = timoutTS.Token;
        await _next(context);
    }
}
0 голосов
/ 04 октября 2018

Как насчет добавления устойчивости и кратковременной обработки ошибок с помощью Polly ?

Polly - это библиотека .NET для обеспечения устойчивости и обработки переходных сбоев, которая позволяет разработчикам выражать политики, такие как Retry, CircuitАвтоматический выключатель, тайм-аут, изоляция переборки и запасной вариант в свободном и поточно-ориентированном виде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...