Files
BuYuHouDuan/Infrastructure/ScheduledService/CronJobService.cs
T
2026-10-12 16:22:04 +08:00

86 lines
2.6 KiB
C#

using Cronos;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace ScheduledService;
public class CronJobService : IHostedService, IDisposable
{
private System.Timers.Timer? _timer;
private readonly CronExpression _expression;
private readonly TimeZoneInfo _timeZoneInfo;
private readonly ILogger<CronJobService> _logger;
public CronJobService(string cronExpression, TimeZoneInfo timeZoneInfo, ILogger<CronJobService>? logger = null)
{
_expression = CronExpression.Parse(cronExpression, CronFormat.IncludeSeconds);
_timeZoneInfo = timeZoneInfo;
_logger = logger ?? NullLogger<CronJobService>.Instance;
}
public virtual async Task StartAsync(CancellationToken cancellationToken)
{
await ScheduleJob(cancellationToken);
}
protected virtual async Task ScheduleJob(CancellationToken cancellationToken)
{
var next = _expression.GetNextOccurrence(DateTimeOffset.Now, _timeZoneInfo);
if (next.HasValue)
{
var delay = next.Value - DateTimeOffset.Now;
if (delay.TotalMilliseconds <= 0)
{
await ScheduleJob(cancellationToken);
return;
}
_timer = new System.Timers.Timer(delay.TotalMilliseconds);
_timer.Elapsed += async (sender, args) =>
{
_timer?.Dispose();
_timer = null;
try
{
if (!cancellationToken.IsCancellationRequested)
await DoWork(cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "定时任务 DoWork 执行异常");
}
try
{
if (!cancellationToken.IsCancellationRequested)
await ScheduleJob(cancellationToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "定时任务 ScheduleJob 调度异常");
}
};
_timer.Start();
}
await Task.CompletedTask;
}
public virtual async Task DoWork(CancellationToken cancellationToken)
{
await Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Stop();
await Task.CompletedTask;
}
public virtual void Dispose()
{
_timer?.Dispose();
}
}