public async Task WriteNewScheduleTargets() { // Decisions about whether the once-daily run target is near enough: if (await WasLastRunToday()) { return; } // This will be an HHmm value such as 1030 or 2200; SchedulerQueue only invokes this // grain at 15-minute intervals, so quit unless we're near or past the run-at time. var paddedUtc = todayUtc.PlusMinutes(5); var paddedTime = paddedUtc.TimeOfDay; var runTargetUtc = await configCache.GetValue(ConstConfigKeys.ScheduleWriterRunTargetUtc); var(runHour, runMinute) = DateTimeAnalysis.GetHourMinute(runTargetUtc); if (paddedUtc.Date == todayUtc.Date && (paddedTime.Hour < runHour || (paddedTime.Hour == runHour && paddedTime.Minute < runMinute))) { return; } // Decision made: yes, write the next day's schedule records. logger.LogInformation($"WriteNewScheduleTargets"); var jobs = await scheduleRepository.GetJobsWithScheduleSettings(); if (jobs.Count == 0) { return; } foreach (var job in jobs) { try { var planner = new TargetPlanner(job, today.Plus(Duration.FromDays(1)), logger); var newSchedules = planner.GetSchedules(); if (newSchedules.Count > 0) { await InsertScheduleRows(newSchedules); } newSchedules = null; } catch { } } await configRepository.UpdateConfig(ConstConfigKeys.ScheduleWriterLastRunDateUtc, InstantPattern.General.Format(today)); }
private void CreateSchedulesForDate() { var todayUtc = SystemClock.Instance.GetCurrentInstant().InUtc(); var targetDateIsToday = (todayUtc.Date == targetDate.InUtc().Date); // When the schedules are being created for the current date, don't // create new schedules targeting times which have already passed. var filterHour = todayUtc.Hour; var filterMinute = todayUtc.Minute; var times = Formatting.SplitCommaSeparatedList(job.ScheduleTimes); switch (job.ScheduleTimeMode) { // every hour at the indicated minutes (eg. 00,15,30,45) case ScheduleTimeMode.Minutes: for (int hour = 0; hour < 24; hour++) { foreach (var min in times) { var minute = int.Parse(min); TryAddUtcEntry(hour, minute); } } break; // specific times: 1130,1400,2245 case ScheduleTimeMode.HoursMinutes: foreach (var time in times) { var(hour, minute) = DateTimeAnalysis.GetHourMinute(time); TryAddUtcEntry(hour, minute); } break; // a single value, every N minutes starting after midnight (eg. 30) case ScheduleTimeMode.Interval: for (int hour = 0; hour < 24; hour++) { int interval = int.Parse(times[0]); for (int minute = 0; minute < 59; minute += interval) { TryAddUtcEntry(hour, minute); } } break; } void TryAddUtcEntry(int hour, int minute) { var local = new LocalDateTime(analysis.Date.Year, analysis.Month, analysis.Day, hour, minute); try { var scheduleTarget = local .InZoneStrictly(jobZone) // TODO make InZoneStrictly vs Leniently a config option .WithZone(DateTimeZone.Utc) .ToDateTimeOffset(); if (!targetDateIsToday || filterHour < scheduleTarget.Hour || (filterHour == scheduleTarget.Hour && filterMinute <= scheduleTarget.Minute)) { newSchedules.Add(new ScheduledJobsTable { DefinitionId = job.Id, ScheduleTarget = scheduleTarget }); } } catch (Exception ex) when(ex is SkippedTimeException || ex is AmbiguousTimeException) { logger?.LogWarning($"Skipping invalid/ambiguous results applying timezone {jobZone.Id} to {LocalDateTimePattern.GeneralIso.Format(local)}"); } } }