ASP.NET 5中RegisterObject / QueueBackgroundWorkItem的等价物

时间:2014-12-28 11:53:37

标签: asp.net-core

In" System.Web" ASP.NET,后台工作可以通过RegisterObject / QueueBackgroundWorkItem注册,以便参与IIS的关闭顺序(完成90秒宽限期),但我很难找到ASP.NET 5中的完全等价物。

查看Microsoft.AspNet.Hosting.HostingEngine的来源,我可以看到它通过IApplicationLifecycle.ApplicationStoppingIApplicationLifecycle.ApplicationStopped发出信号(在它之间配置服务器和PipelineInstance),但是没有#39; t似乎是90秒宽限期内的任何空间,需要旧API中的RegisterObject

IIS集成层尚未开源(如果有的话),因此很难看出该实现如何映射事物。

我错过了API吗?我应该通过CancellationToken.Register()执行阻止关闭吗?这是vnext""" v1的一部分。

任何启蒙都会受到高度赞赏。

1 个答案:

答案 0 :(得分:6)

我使用基于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...");
});