.Net 6使用Hangfire(二)
本文主要介绍如何使用已配置好的HangFire来执行作业调度。
1、Fire-and-forget 即发即弃
立即调用作业并且只执行一次;
当我们调用Hangfire.BackgroundJob.Enqueue的时候,并不是立即调用传入的方法,它会执行以下的几个步骤:
①把作业信息(传入的方法和方法参数)进行序列化;
②基于序列化信息创建后台作业;
③把创建的后台作业信息存储到持久化容器中(通常为数据库);
④把后台作业入队到队列中等待调度;
当这些步骤执行完后,Hangfire.BackgroundJob.Enqueue方法会立即返回到调用者;HangFire的另外一个组件HangFire Server会从持久化容器中查询已入队的后台作业的信息并可靠的执行它们。
已入队的后台作业由专用线程池中的工作线程管理,每个工作线程进行如下处理:
①从队列中获取下一个后台作业并对其它工作线程隐藏;
②执行后台作业和定义在作业上的扩展过滤器(如在作业执行前触发的过滤器、作业执行失败时触发的过滤器等);
③从队列中移除该后台作业;
所以后台作业只有在成功执行后才会从队列中移除,即使后台作业在执行的过程被中断了,HangFire也会执行补偿逻辑来保证每个后台作业的执行(根据持久化容器不同,补偿逻辑不一样)。
1 jobId = Hangfire.BackgroundJob.Enqueue<IHangfireSendEmailJob>(x => x.Send(new EmailSendingArgs 2 { 3 EmailAddress = "9624@qq.com", 4 Subject = "hangfire自带方法立即执行作业", 5 Body = "body" 6 })); 7 8 Hangfire.BackgroundJob.ContinueJobWith(jobId, () => Debug.WriteLine($"{DateTime.Now} 执行完成作业{jobId}"));
2、Schedule 延迟执行
延迟一定时间后执行作业,只执行一次;
HangFire周期性的查询并调度等待执行的后台作业进入相应的队列中,让工作线程执行它们。默认每15s查询一次,你也可以通过设置 SchedulePollingInterval 属性来改变它。
1 Hangfire.BackgroundJob.Schedule<IHangfireSendEmailJob>(x => x.Send(new EmailSendingArgs 2 { 3 EmailAddress = "9624@qq.com", 4 Subject = "hangfire自带方法推迟执行作业", 5 Body = "body" 6 }), TimeSpan.FromSeconds(30));
3、RecurringJob 周期执行
周期性执行作业,支持cron表达式;
创建周期性作业时时,需要指定一个唯一标识符,之后可以用这个唯一标识符来操作这个作业;在某些持久化存储中,可能对标识符的大小写敏感;
调用 AddOrUpdate 方法会创建一个新的周期性作业或者更新已存在的拥有相同标识符的作业;调用方法后会在持久化容器中创建一条新的数据,HangFire中的一个特殊组件会以分钟级别的频率查询周期性的作业并把它们入队,并像Fire-And-Forget作业一样执行。
通过调用 RemoveIfExists
方法,传递唯一标识符来删除已经存在的周期性作业,即使不存在对应的作业也不会抛出异常。
1 RecurringJob.RemoveIfExists("some-id");
1 Hangfire.RecurringJob.AddOrUpdate<IHangfireSendEmailJob>("IHangfireSendEmailJob", x => x.Send(new EmailSendingArgs 2 { 3 EmailAddress = "9624@qq.com", 4 Subject = "hangfire自带方法周期执行作业", 5 Body = "body" 6 }), Hangfire.Cron.Minutely);
调用 Trigger 方法可以立即运行一个周期性的作业,但是这样并不会推迟该作业下次周期执行的时间,触发记录也不会被记录到作业,比如一个每周三触发的作业,你在周五的时候手动触发了,在下周三的时候它也会触发。RecurringJob类是对RecurringJobManger类的封装,如果你想实现更加强大和复杂的功能,可以考虑使用 RecurringJobManger类。
1 RecurringJob.Trigger("some-id");
1 var manager = new RecurringJobManager(); 2 manager.AddOrUpdate("some-id", Job.FromExpression(() => Method()), Cron.Yearly());