protected override async Task ExecuteAsync(CancellationToken stoppingToken) { var cron = WeihanLi.Common.Helpers.Cron.CronExpression.Parse(CronExpression); var next = cron.GetNextOccurrence(); while (!stoppingToken.IsCancellationRequested && next.HasValue) { var now = DateTimeOffset.UtcNow; if (now >= next) { if (ConcurrentAllowed) { _ = ProcessAsync(stoppingToken); next = CronHelper.GetNextOccurrence(CronExpression); if (next.HasValue) { Logger.LogInformation("Next at {next}", next); } } else { var firewall = RedisManager.GetFirewallClient($"Job_{GetType().FullName}_{next:yyyyMMddHHmmss}", TimeSpan.FromMinutes(3)); if (await firewall.HitAsync()) { // 执行 job await ProcessAsync(stoppingToken); next = CronHelper.GetNextOccurrence(CronExpression); if (next.HasValue) { Logger.LogInformation("Next at {next}", next); var delay = next.Value - DateTimeOffset.UtcNow; if (delay > TimeSpan.Zero) { await Task.Delay(delay, stoppingToken); } } } else { Logger.LogInformation("正在执行 job,不能重复执行"); next = CronHelper.GetNextOccurrence(CronExpression); if (next.HasValue) { await Task.Delay(next.Value - DateTimeOffset.UtcNow, stoppingToken); } } } } else { // needed for graceful shutdown for some reason. // 1000ms so it doesn't affect calculating the next // cron occurence (lowest possible: every second) await Task.Delay(next.Value - DateTimeOffset.UtcNow, stoppingToken); } } }
public static void MainTest() { // http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html var nextTickUtc = CronHelper.GetNextOccurrence("0 15 10 * * ?"); var nextTickLocal = CronHelper.GetNextOccurrence("0 15 10 * * ?", TimeZoneInfo.Local); Console.WriteLine($"@utc next tick: {nextTickUtc.GetValueOrDefault().DateTime.ToStandardTimeString()} {Environment.NewLine} local next tick:{nextTickLocal.GetValueOrDefault().DateTime.ToStandardTimeString()}"); var nextTicks = CronHelper.GetNextOccurrences("0 15 10-20 * * ?", TimeSpan.FromHours(6), TimeZoneInfo.Local).Take(5).ToArray(); foreach (var tick in nextTicks) { Console.WriteLine(tick.DateTime.ToStandardTimeString()); } }