给.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;
        
        /// <summary>
        /// 启动任务绑定
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task StartAsync(CancellationToken cancellationToken)
        {
            Common.WriteEmailLog("定时任务被启动", "...start...");
            //绑定定时任务
            //设置延迟时间
             _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(60 * Interval));
            return Task.CompletedTask;
        }

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

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

        /// <summary>
        /// 释放托管资源,释放时触发
        /// </summary>
        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<EmailBackgroundService>();

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

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

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

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

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

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

2、编辑配置

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

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

  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
对于在.NET Core中实现定时任务,有几种不同的方法可供选择: 1. 使用System.Threading.Timer:可以使用`System.Threading.Timer`类创建一个定时器,指定要定期执行的方法以及执行间隔。例如: ```csharp using System; using System.Threading; public class Program { public static void Main() { Timer timer = new Timer(DoSomething, null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); // 阻止主线程退出 Console.ReadKey(); } private static void DoSomething(object state) { // 执行定时任务的逻辑 Console.WriteLine("定时任务执行了!"); } } ``` 上述代码中,`DoSomething`方法将每隔10秒被执行一次。 2. 使用Hangfire:Hangfire是一个.NET的开源库,提供了一个简单的方式来执行后台作业,包括定时任务。首先,你需要在项目中安装Hangfire。然后,在Startup类的ConfigureServices方法中配置Hangfire服务: ```csharp using Hangfire; using Hangfire.SqlServer; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; public class Startup { private readonly IConfiguration _configuration; public Startup(IConfiguration configuration) { _configuration = configuration; } public void ConfigureServices(IServiceCollection services) { // 添加Hangfire服务 services.AddHangfire(configuration => configuration.UseSqlServerStorage(_configuration.GetConnectionString("HangfireConnection"))); // ... } public void Configure(IApplicationBuilder app) { // ... // 启用Hangfire仪表板 app.UseHangfireDashboard(); // 启用Hangfire后台处理 app.UseHangfireServer(); // ... } } ``` 然后,在任何需要执行定时任务的地方,你可以使用Hangfire的`RecurringJob`类来定义定时任务: ```csharp using Hangfire; public class MyJob { [AutomaticRetry(Attempts = 3)] // 可选:定义任务失败重试的次数 public static void DoSomething() { // 执行定时任务的逻辑 Console.WriteLine("定时任务执行了!"); } } public class Program { public static void Main() { // 使用Hangfire调度定时任务 RecurringJob.AddOrUpdate<MyJob>("MyJob", x => x.DoSomething(), Cron.Minutely); // 阻止主线程退出 Console.ReadKey(); } } ``` 上述代码中,`DoSomething`方法将按照每分钟一次的频率被调度执行。 这些只是.NET Core中实现定时任务的一些常见方法,你可以根据自己的需求选择合适的方式来实现。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值