После некоторых исследований я решил использовать QueueBackgroundWorkItem
. Это запланирует фоновую задачу, которая не зависит от потока запроса, и, следовательно, будет продолжать выполняться после завершения запроса.
Примечание: Это не постоянная система очередей (она не будет хранить их, например, при перезапуске веб-процесса), но поскольку это просто закрытие соединенияэто нормально для этого сценария.
Реализация
Когда к моему сервису делается запрос, он использует класс static
для получения одного клиента (доступ контролируется с помощью Mutex
) и введите команду.Затем он вызывает эту процедуру:
private static void CreateTimeoutCheck()
{
Action<CancellationToken> workItem = TimeoutConnection;
System.Web.Hosting.HostingEnvironment.QueueBackgroundWorkItem(workItem);
Log.Information("A timeout check has been created");
}
Это вызовет этот метод в фоновом режиме:
/// <summary>
/// Job that runs in background, waits 10 seconds then attempts to close the client
/// </summary>
/// <param name="cancellationToken"></param>
private static async void TimeoutConnection(CancellationToken cancellationToken)
{
Log.Information("Timeout check waiting...");
await Task.Delay(timeoutMS);
Log.Information("Timeout check being made");
CheckForTimeout();
}
Единственное, что меня беспокоит в этом подходе, это то, что я порождаю одинрабочий элемент в пуле потоков на запрос, и если служба интенсивно используется, это может вызвать проблему.Однако каждый из них просто выполняет асинхронное ожидание, поэтому я надеюсь, что это не вызовет проблемы.Служба используется внутренне, поэтому мы контролируем количество / частоту запросов к ней - я бы больше волновался, если бы это было обнаружено извне.
Метод CheckForTimeout
довольно прост:
/// <summary>
/// Check to see if we have had more recent commands
/// </summary>
private static void CheckForTimeout()
{
var secsSinceLastCmd = DateTime.Now.Subtract(_lastCommand).TotalSeconds;
if (secsSinceLastCmd >= clientTimeoutSecs)
{
// logout and close client
Log.Information($"Client timeout: {secsSinceLastCmd:0.0} sec since last command");
CloseClient();
}
}
Я собираюсь некоторое время следить за обновленным сервисом, чтобы убедиться, что он работает нормально, но пока тесты показывают, что он работает как положено.