给.net core安排后台定时任务,并且解决iis自动回收导致任务被终止的问题

1、在 ASP.NET Core 中使用托管服务实现后台任务

很多时候我们需要给程序添加一些后台任务,帮我处理一些需要定时处理的任务,比如定时发送邮件,定时做一些统计之类的工作,这时候我们可以写一个windows服务来搞定,或者在现有的webapi项目中添加定时。

写windows服务来处理后台任务固然是个比较好的选择,但是这样就会增加运维成本,原本只有一个项目,现在有两个,最主要的是windows服务很容易被遗忘掉,升级或者迁移的时候增加风险,对于一些比较简单的任务,我选择直接在 ASP.NET Core 中使用托管服务实现后台任务,非常的简单。这样就可以在一起维护和管理。

编写一个定时任务有两个步骤:

1、实现IHostedService,IDisposable这两个接口,或者直接继承BackgroundService抽象类(因为它实现IHostedService,IDisposable),看代码:

    //实现接口:IHostedService,IDisposable
    public class EmailBackgroundService : IHostedService,IDisposable
    {
        //定义一个定时器
        private Timer _timer;
        
        /// 
        /// 启动任务绑定
        /// 
        /// 
        /// 
        public Task StartAsync(CancellationToken cancellationToken)
        {
            Common.WriteEmailLog("定时任务被启动", "...start...");
            //绑定定时任务
            //设置延迟时间
             _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(60 * Interval));
            return Task.CompletedTask;
        }

        /// 
        /// 定时执行的操作,绑定到定时器上
        /// 
        /// 
        /// 
        private void DoWork(object state)
        {
            Common.WriteEmailLog("定时任务被触发", "开始一波邮件发送");
            try
            {
                //一波操作
            }
            catch (Exception ex)
            {
                Common.WriteEmailLog("定时发送邮件时报错", ex.Message);
            }
        }

        /// 
        /// 任务关闭时执行
        /// 
        /// 
        /// 
        public Task StopAsync(CancellationToken cancellationToken)
        {
            Common.WriteEmailLog("定时任务被关闭", "...end...");
            _timer?.Change(Timeout.Infinite, 0);
            return Task.CompletedTask;
        }

        /// 
        /// 释放托管资源,释放时触发
        /// 
        public void Dispose()
        {
            Common.WriteEmailLog("定时任务被释放闭", "...Dispose...");
            _timer?.Dispose();
            //iis会回收这个定时任务,这边在回收的时候触发一个请求,来再次唤醒该服务
            Thread.Sleep(5000);
            HttpHelper.HttpGet(_configuration.GetSection("AwakenUrl").Value);
        }
    }

2、在Startup类中注册后台任务:

//配置后台任务
//services.AddTransient(typeof(Microsoft.Extensions.Hosting.IHostedService), typeof(EmailBackgroundService));
services.AddHostedService();

2、解决iis自动回收导致任务被终止的问题

IIS会定时回收,类似于自动重新启动网站,我们都有知道网站启动后第一次访问往往会比较慢,网站启动后没有访问,过段时间iis会回收,请求再来的时候会和网站刚刚启动的时候一样,需要等待一段时间,很不舒服,这个就是因为iis回收导致的。

定时回收除了会出现上面的情况外,还会将我们托管的后台任务回收掉,导致我们的后台任务终止执行,直到进来一个请求(网站内任意地址)任务启动,那么如果请求很久没来,这个任务将无法被启动,错过任务应该执行的档口。虽然我们可以通过调整自动回收的时间,甚至设置他不自动回收,但这样始终不是最好的解决方案。

定时任务是托管的资源,实现了IDisposable接口,并且实现了Dispose()方法,这个方法在回收的时候会被触发。通过这一点我们可以在Dispose()方法中,再请求一下我们的网站或接口(请求地址尽量选择资源消耗比较小的),通过访问这样一个请求,我们服务又会起来。

上面红字部分是我原先介绍的一种方法,没有做过全面的测试就搬上来,最近发现它同样会停掉,特地来说明一下,希望大家不要走弯路,这边我再介绍另外一个方案,就是通过配置iis来实现预加载,即在资源被回收的情况下,通过一个链接来唤醒自身,这样首次访问的时候不会觉得卡顿,并且我们被回收掉的定时任务又会重新的启动起来,一举两得,具体的配置方法如下:

1、设置网站的启用预加载:

给.net core安排后台定时任务,并且解决iis自动回收导致任务被终止的问题_第1张图片

2、编辑配置

给.net core安排后台定时任务,并且解决iis自动回收导致任务被终止的问题_第2张图片

给.net core安排后台定时任务,并且解决iis自动回收导致任务被终止的问题_第3张图片

3、设置应用程序池 启动模式为:AlwaysRunning

给.net core安排后台定时任务,并且解决iis自动回收导致任务被终止的问题_第4张图片

经过上面的一顿操作,就配置好了,为了保险起见,设置定时任务一定要留心它的运行情况,以免产生不必要的麻烦,最好记录日志,关注下夜间网站闲置,被回收时的运行情况,保证稳定,如果你的任务仍有异常,那么最好写一个服务来跑定时任务。

你可能感兴趣的:(asp.net,core,随笔,.net,core后台任务,iis回收,定时任务)