private DateTime ComputeDue(ComputedCronJob computedJob, DateTime now) { computedJob.UpdateNext(now); var retryBehavior = computedJob.RetryBehavior ?? RetryBehavior.DefaultRetry; var retries = computedJob.Retries; if (retries == 0) { return(computedJob.Next); } var realNext = computedJob.Schedule.GetNextOccurrence(now); if (!retryBehavior.Retry) { // No retry. If job failed before, we don't care, just schedule it next as usual. return(realNext); } if (retries >= retryBehavior.RetryCount) { // Max retries. Just schedule it for the next occurance. return(realNext); } // Delay a bit. return(computedJob.FirstTry.AddSeconds(retryBehavior.RetryIn(retries))); }
private async Task RunAsync(ComputedCronJob computedJob, ProcessingContext context) { var storage = context.Storage; var retryBehavior = computedJob.RetryBehavior; while (!context.IsStopping) { var now = DateTime.UtcNow; var due = ComputeDue(computedJob, now); var timeSpan = due - now; if (timeSpan.TotalSeconds > 0) { await context.WaitAsync(timeSpan); } context.ThrowIfStopping(); using (var scopedContext = context.CreateScope()) { var factory = scopedContext.Provider.GetService <IJobFactory>(); var job = (IJob)factory.Create(computedJob.JobType); var success = true; try { var sw = Stopwatch.StartNew(); await job.ExecuteAsync(); sw.Stop(); computedJob.Retries = 0; _logger.CronJobExecuted(computedJob.Job.Name, sw.Elapsed.TotalSeconds); } catch (Exception ex) { success = false; if (computedJob.Retries == 0) { computedJob.FirstTry = DateTime.UtcNow; } computedJob.Retries++; _logger.CronJobFailed(computedJob.Job.Name, ex); } if (success) { now = DateTime.UtcNow; computedJob.Update(now); using (var scope = _provider.CreateScope()) { var provider = scope.ServiceProvider; var connection = provider.GetRequiredService <IStorageConnection>(); await connection.UpdateCronJobAsync(computedJob.Job); } } } } }
public void UpdateNext_LastRun_AfterPrev_SchedulesNormal() { // Arrange var now = new DateTime(2000, 1, 1, 8, 0, 0); var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromSeconds(5))); var computed = new ComputedCronJob(cronJob); // Act computed.UpdateNext(now); // Assert computed.Next.Should().BeAfter(now); }
public void UpdateNext_LastRun_BeforePrev_SchedulesNow() { // Arrange var now = new DateTime(2000, 1, 1, 8, 0, 0); var cronJob = new CronJob(Cron.Daily(), now.Subtract(TimeSpan.FromDays(2))); var computed = new ComputedCronJob(cronJob); // Act computed.UpdateNext(now); // Assert computed.Next.Should().Be(now); }
public void UpdateNext_LastRunNever_SchedulesNow() { // Arrange var now = new DateTime(2000, 1, 1, 8, 0, 0); var cronJob = new CronJob(Cron.Daily()); var computed = new ComputedCronJob(cronJob); // Act computed.UpdateNext(now); // Assert computed.Next.Should().Be(now); }