初步TimedTask完成

This commit is contained in:
Falcon 2025-02-19 15:57:34 +08:00
parent 3805d2b645
commit 4bb1064352
2 changed files with 157 additions and 0 deletions
Falcon.SugarApi/TimedBackgroundTask

View File

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
namespace Falcon.SugarApi.TimedBackgroundTask
{
/// <summary>
/// 服务集合扩展方法
/// </summary>
public static class IServiceCollectionExtend
{
/// <summary>
/// 向HostService中注册TimedBackgroundTask服务
/// </summary>
/// <typeparam name="T">TimedBackgroundTask的具体类型</typeparam>
/// <param name="services">服务集合</param>
/// <returns>服务集合</returns>
public static IServiceCollection AddTimedBackgroundTask<T>(this IServiceCollection services)
where T : TimedTask {
services.AddHostedService<T>();
return services;
}
}
}

View File

@ -0,0 +1,135 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Falcon.SugarApi.TimedBackgroundTask
{
/// <summary>
/// 由定时器驱动的后台任务
/// </summary>
public class TimedTask:BackgroundService, IDisposable
{
/// <summary>
/// 日志记录器
/// </summary>
protected readonly ILogger? Logger;
/// <summary>
/// 心跳计时器
/// </summary>
private readonly PeriodicTimer _timer;
/// <summary>
/// 运行一次任务
/// </summary>
/// <param name="cancellationToken">退出信号</param>
/// <returns>如果继续执行返回True否则False</returns>
public virtual async Task<bool> Run(CancellationToken cancellationToken) => await Task.FromResult(true);
/// <summary>
/// Timer心跳
/// </summary>
public virtual int Heartbeat { get; set; } = 1;
/// <summary>
/// 执行计划的Cron串
/// </summary>
public virtual string CronSchedule { get; set; } = "30 * * * * *";
/// <summary>
/// 获取下次执行任务的计划
/// </summary>
public CronExpression Schedule { get; private set; }
/// <summary>
/// 任务正在运行
/// </summary>
private bool _isRunning = false;
/// <summary>
/// 下次执行时间
/// </summary>
public DateTime NextTickTime { get; set; } = DateTime.MinValue;
/// <summary>
/// 后台任务开始
/// </summary>
protected virtual void OnStart(TimedTask t,CancellationToken stoppingToken) { }
/// <summary>
/// 后台任务停止
/// </summary>
protected virtual void OnStop(TimedTask t,CancellationToken stoppingToken) { }
/// <summary>
/// 完成一次执行
/// </summary>
protected virtual void OnCompleted(TimedTask t,CancellationToken stoppingToken) { }
/// <summary>
/// 执行中发生未处理异常
/// </summary>
protected virtual bool OnException(TimedTask t,Exception ex,CancellationToken stoppingToken) {
return false;
}
/// <summary>
/// 系统服务
/// </summary>
public IServiceProvider Service { get; set; }
/// <summary>
/// 资源锁
/// </summary>
private static object _lock = new object();
/// <summary>
/// 构造Timed后台任务
/// </summary>
/// <param name="service">服务提供器</param>
public TimedTask(IServiceProvider service) {
this.Service = service;
this.Logger = service.GetService(typeof(ILogger<>).MakeGenericType(GetType())) as ILogger;
_timer = new PeriodicTimer(TimeSpan.FromSeconds(this.Heartbeat));
this.Schedule = new CronExpression(this.CronSchedule);
}
/// <summary>
/// 由系统调度执行任务
/// </summary>
/// <param name="stoppingToken">退出信号</param>
/// <returns>无返回</returns>
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
this.OnStart(this,stoppingToken);
while(await _timer.WaitForNextTickAsync(stoppingToken)) {
lock(_lock) {
if(stoppingToken.IsCancellationRequested) {
break;
}
if(this._isRunning || DateTime.Now < this.NextTickTime) {
continue;
}
this._isRunning = true;
}
try {
var goOn = await this.Run(stoppingToken);
this.OnCompleted(this,stoppingToken);
if(goOn) {
continue;
}
}
catch(Exception ex) {
this.OnException(this,ex,stoppingToken);
}
SetNextTick();
this._isRunning = false;
}
this.OnStop(this,stoppingToken);
}
private void SetNextTick(string? cronSchedule = null) {
var s = cronSchedule == null ? this.Schedule : new CronExpression(cronSchedule);
this.NextTickTime = s.GetNextOccurrence(DateTime.Now);
}
public override void Dispose() {
this._timer?.Dispose();
base.Dispose();
}
}
}