在"System.Web"ASP.NET 中,可以通过RegisterObject
/QueueBackgroundWorkItem
注册后台工作,以便参与IIS的关闭序列(完成90秒宽限期),但我正在努力在第5 ASP.NET 中找到完全相同的等价物。
查看Microsoft.AspNet.Hosting.HostingEngine
的源代码,我可以看到它通过 IApplicationLifecycle.ApplicationStopping
和 IApplicationLifecycle.ApplicationStopped
发出信号(它PipelineInstance
之间释放服务器和 ),但似乎没有任何空间用于需要在旧 API 中RegisterObject
的 90 秒宽限期。
IIS 集成层尚未开源(如果有的话),因此很难看出该实现如何映射事物。
我是否缺少 API?我应该通过CancellationToken.Register()
执行阻塞关闭吗?这是"vNext 的 v1"遗漏的东西吗?
任何启发将不胜感激。
我使用基于Katana的Hangfire实现作为灵感创建了以下内容。除了检查 IIS Express 终止时关闭代码是否运行之外,它没有其他测试,但它可以用作概念证明。
这里的设计显然不是用于"即发即弃"任务,因为它们可以在关闭之前触发。但是,它确实适用于幂等队列处理器之类的东西(假设已禁用空闲关闭超时)
public static class BackgroundServiceExtensions
{
public static void UseBackgroundService(
this IApplicationBuilder builder, Func<CancellationToken, Task> service)
{
var lifetime = (IApplicationLifetime)builder.ApplicationServices
.GetService(typeof(IApplicationLifetime));
var stoppingToken = lifetime.ApplicationStopping;
var stoppedToken = lifetime.ApplicationStopped;
// This, in particular, would need to be properly thought out,
// preferably including an execution context to minimise threadpool use
// for async-heavy background services
Task serviceTask = Task.Run(() => service(stoppingToken));
stoppedToken.Register(() =>
{
try
{
// Block (with timeout) to allow graceful shutdown
if (!serviceTask.Wait(TimeSpan.FromSeconds(30)))
{
// Log: Background service didn't gracefully shutdown.
// It will be terminated with the host process
}
}
catch(Exception)
{
// Ignored
}
});
}
}
然后可以这样使用:
app.UseBackgroundService(async cancellationToken =>
{
while (!cancellationToken.IsCancellationRequested)
{
System.Diagnostics.Debug.WriteLine("Tick...");
try
{
// Use cancellationToken for anything that is (logically) cancellable
await Task.Delay(1000, cancellationToken);
}
catch(TaskCanceledException)
{ }
}
System.Diagnostics.Debug.WriteLine("Cancellation requested, shutting down...");
});