• .net core hangfire


    与quartz.net对比

    在项目没有引入Hangfire之前,一直使用的是Quartz.net。Quartz.net在定时任务处理方面优势如下:

    • 支持秒级单位的定时任务处理,但是Hangfire只能支持分钟及以上的定时任务处理

    原因在于Hangfire用的是开源的NCrontab组件,跟linux上的crontab指令相似。

    • 更加复杂的触发器,日历以及任务调度处理

    • 可配置的定时任务

    但是为什么要换Hangfire? 很大的原因在于项目需要一个后台可监控的应用,不用每次都要从服务器拉取日志查看,在没有ELK的时候相当不方便。Hangfire控制面板不仅提供监控,也可以手动的触发执行定时任务。如果在定时任务处理方面没有很高的要求,比如一定要5s定时执行,Hangfire值得拥有。抛开这些,Hangfire优势太明显了:

    • 持久化保存任务、队列、统计信息

    • 重试机制

    • 多语言支持

    • 支持任务取消

    • 支持按指定Job Queue处理任务

    • 服务器端工作线程可控,即job执行并发数控制

    • 分布式部署,支持高可用

    • 良好的扩展性,如支持IOC、Hangfire Dashboard授权控制、Asp.net Core、持久化存储等

    这里演示在asp.net core使用Redis作为Hangfire的持久化存储

    1、引用包

    Hangfire.AspNetCore

    Hangfire.Redis.StackExchange

    2、注入hangfire及配置

    这里说明下 services.AddHostedService<MyJob1>();是定时任务,继承自BackgroundService。

    然后在configure中引入hangfire。如果在这里不引入队列的名字,会导致添加的任务无法加入到队列。

     app.UseHangfireDashboard();表示使用看板功能。

     3、普通使用,比如添加任务到队列或者添加延时任务,基本是一样的。

    这里在接口中直接演示,直接使用BackgroundJob.Enqueue将方法添加到队列。

    注意队列名称要使用小写,被添加到队列中的方法需要是Public的。

    4、定时任务

    定义定时任务配置类

     /// <summary>
        /// 工作任务配置
        /// </summary>
        public class WorkerConfig
        {
            /// <summary>
            /// 轮询秒数
            /// </summary>
            public int IntervalSecond { get; set; }
            /// <summary>
            /// 工作唯一编号
            /// </summary>
            public string WorkerId { get; set; }
            /// <summary>
            /// 队列名称
            /// </summary>
            public string QueuesName { get; set; }
            /// <summary>
            /// 表达式
            /// </summary>
            public string Cron { get; set; }
        }

    定义需要定时执行的接口方法

    /// <summary>
        /// 所有的后台工作者类都应实现该接口
        /// </summary>
        public interface IBackgroundWorkerDo
        {
            /// <summary>
            /// 执行具体的任务
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            Task DoWorkAsync(PerformContext context);
        }

    定义hangfire基类,定时任务的类都继承该类。

     public abstract class HangfireWorkerPxoxy:BackgroundService
        {
            private readonly IConfiguration _appConfiguration;
            private readonly WorkerConfig _config;
            public HangfireWorkerPxoxy(IConfiguration appConfiguration, WorkerConfig Config)
            {
                _appConfiguration = appConfiguration;
                _config = Config;
            }
            
            public void Excete<T>() where T : IBackgroundWorkerDo
            {
                var appsetting = _appConfiguration.GetSection("Appsetting").Get<Appsetting>();
                var options = new RedisStorageOptions
                {
                    Db = appsetting.RedisConfig.Defaultdatabase,
                    SucceededListSize = 50000,
                    DeletedListSize = 50000,
                    ExpiryCheckInterval = TimeSpan.FromHours(1),
                    InvisibilityTimeout = TimeSpan.FromHours(3)
                };
                var redisString = appsetting.RedisConfig.HostName + ":" + appsetting.RedisConfig.Port + ",defaultdatabase="+ appsetting.RedisConfig.Defaultdatabase;
                JobStorage.Current = new RedisStorage(redisString);
                var manager = new RecurringJobManager(JobStorage.Current);
                string workerId = _config.WorkerId;
                string cron = string.IsNullOrEmpty(_config.Cron) ? Cron.MinuteInterval(_config.IntervalSecond / 60) : _config.Cron;
                manager.RemoveIfExists(workerId);
                manager.AddOrUpdate(workerId, Job.FromExpression<T>((t) => t.DoWorkAsync(null)), cron, TimeZoneInfo.Local, string.IsNullOrEmpty(_config.QueuesName) ? "default" : _config.QueuesName);
            }

    定义最终的定时任务类

      /// <summary>
        ///  定时任务
        /// </summary>
        class MyJob1 : HangfireWorkerPxoxy,IBackgroundWorkerDo
        {
            private readonly ILogger _logger;
          
            public MyJob1(IConfiguration _appConfiguration, ILogger<MyJob1> logger) : base(_appConfiguration, new WorkerConfig { IntervalSecond = 60 * 1, WorkerId = "RealWorker", QueuesName = "queue1" })
            {
                _logger = logger;
            }
    
            /// <summary>
            ///  添加同步sku库存任务
            /// </summary>
            public  async Task DoWorkAsync(PerformContext context)
            {
                var temp = await Task.FromResult(0);
                if (context == null)
                {
                    return ;
                }
                _logger.LogInformation($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 开始添加同步数据任务 ...");
               
                Thread.Sleep(1000*10);
                _logger.LogInformation($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} 结束添加同步数据任务 ...");
            }
    
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                var temp= await Task.FromResult(0);
                Excete<MyJob1>();
            }
    
            
        }

    注入定时任务类,services.AddHostedService<MyJob1>();

    最后看下效果。

    ok,大功告成。

  • 相关阅读:
    html_Dom
    html_javascript
    html_之css
    协程
    进程和线程的总结
    html_基础标签
    html_头部<meta>设置
    Python_queue单项队列
    Python_paramiko模块
    Python_多进程multiprocessing
  • 原文地址:https://www.cnblogs.com/KQNLL/p/11875171.html
Copyright © 2020-2023  润新知