TimedTask使用进准的计时器方式而非轮训方式。

This commit is contained in:
Falcon 2025-03-06 14:38:16 +08:00
parent 7350a60bb2
commit 2fec21a3ea

View File

@ -10,16 +10,12 @@ namespace Falcon.SugarApi.TimedTask
/// <summary> /// <summary>
/// 由定时器驱动的后台任务 /// 由定时器驱动的后台任务
/// </summary> /// </summary>
public abstract class TimedTask:BackgroundService, IDisposable public abstract class TimedTask:BackgroundService
{ {
/// <summary> /// <summary>
/// 日志记录器 /// 日志记录器
/// </summary> /// </summary>
protected readonly ILogger? Logger; protected readonly ILogger? Logger;
/// <summary>
/// 心跳计时器
/// </summary>
private readonly PeriodicTimer _timer;
/// <summary> /// <summary>
/// 运行一次任务 /// 运行一次任务
@ -34,20 +30,11 @@ namespace Falcon.SugarApi.TimedTask
/// </summary> /// </summary>
protected abstract string CronSchedule { get; } protected abstract string CronSchedule { get; }
/// <summary>
/// Timer心跳 毫秒
/// </summary>
public virtual int Heartbeat { get; protected set; } = 1000;
/// <summary> /// <summary>
/// 获取下次执行任务的计划 /// 获取下次执行任务的计划
/// </summary> /// </summary>
protected CronExpression Schedule { get; private set; } protected CronExpression Schedule { get; private set; }
/// <summary>
/// 任务正在运行
/// </summary>
private bool _isRunning = false;
/// <summary> /// <summary>
/// 下次执行时间 /// 下次执行时间
/// </summary> /// </summary>
@ -83,10 +70,6 @@ namespace Falcon.SugarApi.TimedTask
/// 系统服务 /// 系统服务
/// </summary> /// </summary>
public IServiceProvider Service { get; set; } public IServiceProvider Service { get; set; }
/// <summary>
/// 资源锁
/// </summary>
private static object _lock = new object();
/// <summary> /// <summary>
/// 构造Timed后台任务 /// 构造Timed后台任务
@ -95,7 +78,6 @@ namespace Falcon.SugarApi.TimedTask
public TimedTask(IServiceProvider service) { public TimedTask(IServiceProvider service) {
this.Service = service; this.Service = service;
this.Logger = service.GetService(typeof(ILogger<>).MakeGenericType(GetType())) as ILogger; this.Logger = service.GetService(typeof(ILogger<>).MakeGenericType(GetType())) as ILogger;
_timer = new PeriodicTimer(TimeSpan.FromMilliseconds(this.Heartbeat));
this.Schedule = new CronExpression(this.CronSchedule); this.Schedule = new CronExpression(this.CronSchedule);
} }
@ -108,49 +90,35 @@ namespace Falcon.SugarApi.TimedTask
if(!this.OnStart(this,stoppingToken)) { if(!this.OnStart(this,stoppingToken)) {
return; return;
} }
while(await _timer.WaitForNextTickAsync(stoppingToken)) { try {
lock(_lock) { while(!stoppingToken.IsCancellationRequested) {
DateTime nextRunTime = Schedule.GetNextOccurrence(DateTime.Now);
TimeSpan delay = nextRunTime - DateTime.Now;
if(delay > TimeSpan.Zero) {
await Task.Delay(delay,stoppingToken);
}
if(stoppingToken.IsCancellationRequested) { if(stoppingToken.IsCancellationRequested) {
break; break;
} }
if(this._isRunning) { // 执行任务
continue; try {
var goOn = await this.Run(stoppingToken);
var comResult = this.OnCompleted(this,stoppingToken);
if(!goOn || !comResult) {
break;
}
} }
if(DateTime.Now < this.NextTickTime) { catch(Exception ex) {
continue; if(!this.OnException(this,ex,stoppingToken)) {
break;
}
} }
this._isRunning = true; //Schedule = new CronExpression(this.CronSchedule);
} }
try {
var goOn = await this.Run(stoppingToken);
var comResult = this.OnCompleted(this,stoppingToken);
if(!goOn || !comResult) {
break;
}
}
catch(Exception ex) {
if(!this.OnException(this,ex,stoppingToken)) {
break;
}
}
SetNextTick();
this._isRunning = false;
} }
this.OnStop(this,stoppingToken); finally {
} 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);
}
/// <summary>
/// 释放对象
/// </summary>
public override void Dispose() {
this._timer?.Dispose();
GC.SuppressFinalize(this);
base.Dispose();
} }
} }
} }