.Net Core 简单定时任务框架封装

  有段日子没有更新,写点东西冒个泡 。这篇文章过来讲个小东西,也是大家在日常开发中也经常需要面临的问题:后台定时任务处理。估计大家看到这句就已经联想到 QuartZ 等类似第三方类库了,不好意思,后边的事情和它们没有关系。这里要展开的是用.Net Core 下的 Generic Host 配合封装简版定时任务处理框架的过程。至于什么是Generic Host,简单来说就是一个简化版不含Http管道等的非Web应用托管宿主服务,至于它如何来,其内有着什么样的实现细节,官方介绍已经足够。这篇文章主要还是回到实际的基础封装过程实现层面,用一个小东西来演示如何在常见业务代码中梳理职责,内容主要如下:

1.  概要分解

2.  封装实现

3.   示例演示

4.   注意事项

 一. 概要分解

  如果对Generic Host 已经有了解的同学可能也看过网上其他文章,大多也都介绍用它如何实现定时任务处理。这些文章基本提供了一个通用实现,对业务实现还是稍显啰嗦。这两天整理逻辑有个任务不得不临时定时处理,想到这个东西,花了点时间处理了下,东西不复杂不过还是想把这个思路分享给需要的朋友。

  定时任务,分解来看特别简单,就是两个维度“  定时 +  任务 ”,如果还有另外一个维度,那就是 任务运行的托管服务。在托管平台上添加定时规则,根据规则触发任务,工作结束。

  1.  关于定时,主要就是一套任务触发的规则,其作为一个调度者,只需要关心的是 在什么时间,以何种频率 触发任务。   在.Net 下我们通过定时器(Timer - 构造函数包含这两个核心参数,.net 下有两个Timer实现,一个是System.Timer.Timer,一个是System.Threading.Timer, 这里用的第二者,自由度更高)来实现,但是它不应该直接和具体的任务挂钩,使用方也不应该每次都自己来处理Timer的初始化及相关回收释放等相同操作,我们需要的是使用方只需告知框架层要执行什么任务,和任务对应的时间规则。

  2.  关于任务, 这个角色是一个任务的执行者, 定时调度者 告诉 任务执行者 在什么时候开始执行和结束任务,其本身不会关注调度的实现。

  3.  关于托管服务,也就是已经说过的Generic Host,当然你也可以使用windows服务等。它的职责就是保证给任务提供执行环境,并告诉任务定时器当前服务在什么时候开始运行和关闭。  实现时提供了统一 IHostedService  接口,具体实现下边实现会有展示。Generic Host 启动方式有两种形式:

    a. 如果是.NetCore 站点,默认已经包含,只需要在 ConfigureServices 时注册具体实现即可。

    b. 可以独立创建,比如控制台通过 new HostBuilder() 形式启动,具体参见官方文档。

  为了更直观的展示相关之间的关系,这里我画了个类图来分解相关的职责,同时也是后边具体实现的主要内容:

.Net Core 简单定时任务框架封装

 二.  封装实现

  从上边类图可以看出当前基础框架主要由 BaseJobTrigger(触发器基类),IJobExcutor(任务执行者接口),ListJobExcutor<IType>(通用列表循环任务执行者基类)。下边分别就上边三者贴出具体实现。

  1.  BaseJobTrigger(触发器基类),实现代码如下:

public abstract class BaseJobTrigger : IHostedService, IDisposable { private Timer _timer; private readonly TimeSpan _dueTime; private readonly TimeSpan _periodTime; private readonly IJobExecutor _jobExcutor; /// <summary> /// 构造函数 /// </summary> /// <param>到期执行时间</param> /// <param>间隔时间</param> /// <param>任务执行者</param> protected BaseJobTrigger(TimeSpan dueTime, TimeSpan periodTime, IJobExecutor jobExcutor) { _dueTime = dueTime; _periodTime = periodTime; _jobExcutor = jobExcutor; } #region 计时器相关方法 private void StartTimerTrigger() { if (_timer == null) _timer = new Timer(ExcuteJob,_jobExcutor,_dueTime, _periodTime); else _timer.Change(_dueTime, _periodTime); } private void StopTimerTrigger() { _timer?.Change(Timeout.Infinite, Timeout.Infinite); } private void ExcuteJob(object obj) { try { var excutor = obj as IJobExecutor; excutor?.StartJob(); } catch (Exception e) { LogUtil.Error($"执行任务({nameof(GetType)})时出错,信息:{e}"); } } #endregion /// <summary> /// 系统级任务执行启动 /// </summary> /// <returns></returns> public virtual Task StartAsync(CancellationToken cancellationToken) { try { StartTimerTrigger(); } catch (Exception e) { LogUtil.Error($"启动定时任务({nameof(GetType)})时出错,信息:{e}"); } return Task.CompletedTask; } /// <summary> /// 系统级任务执行关闭 /// </summary> /// <returns></returns> public virtual Task StopAsync(CancellationToken cancellationToken) { try { _jobExcutor.StopJob(); StopTimerTrigger(); } catch (Exception e) { LogUtil.Error($"停止定时任务({nameof(GetType)})时出错,信息:{e}"); } return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzffds.html