private static ActorScheduleOptions RemoveFlag(ActorScheduleOptions options, ActorScheduleOptions toRemove) { if (options.HasFlag(toRemove)) { return(options ^ toRemove); } else { return(options); } }
public void ShouldBeAbleToScheduleWorkToRepeatAtAFixedInterval(WorkType workType, ActorScheduleOptions actorScheduleOptions) { var barrier = new TaskCompletionSource <bool>(); var expectedInterval = TimeSpan.FromMilliseconds(100); var times = new List <DateTime>(); var sampleSize = 5; void Adder() { if (times.Count < sampleSize) { times.Add(DateTime.UtcNow); } if (times.Count == sampleSize) { // Block here so that we can assess something that's not moving barrier.Task.Wait(); } } switch (workType) { case WorkType.Sync: _scheduler.Schedule((Action)Adder, expectedInterval, actorScheduleOptions); break; case WorkType.Async: _scheduler.Schedule(async() => { await Task.Yield(); Adder(); }, expectedInterval, actorScheduleOptions); break; default: throw new Exception($"Unhandled test case {workType}."); } Within.FiveSeconds(() => times.Count.Should().Be(sampleSize)); var actualIntervals = times.Take(sampleSize - 1).Zip(times.Skip(1), (x, y) => y - x).ToList(); // Use 75ms instead of 100ms to give it a bit of latitude: mainly we just want to make sure there is some delaying going on. actualIntervals.Should().OnlyContain(x => x >= TimeSpan.FromMilliseconds(75)); barrier.SetResult(true); }
/// <summary> /// A wrapper round IActorWorkScheduler.Schedule() that reschedules work after an unxexpected error has occurred in that work. /// </summary> /// <param name="self">The schedule.</param> /// <param name="work">The work to perform repeatedly.</param> /// <param name="interval">Interval at which the work is to be repeated.</param> /// <param name="options">Options. See <see cref="ActorScheduleOptions"/> for details.</param> /// <param name="unexpectedErrorHandler">Handler for any unexpected exception.</param> /// <returns>A task: the only possible completion is due to cancellation.</returns> public static Task Schedule(this IActorWorkScheduler self, Func <Task> work, TimeSpan interval, ActorScheduleOptions options, Action <Exception> unexpectedErrorHandler) { return(ScheduleImpl(self.Schedule(work, interval, options), () => self.Schedule(work, interval, RemoveFlag(options, ActorScheduleOptions.NoInitialDelay)), unexpectedErrorHandler)); }