public void ItExecutesTasksAtTheSpecifiedInterval() { var semaphoreFile = Path.GetTempFileName(); File.Delete(semaphoreFile); var intervalSeconds = 2; var taskScheduler = new TaskScheduler(TaskQueue.Redis("localhost:6379")); taskScheduler.AddScheduledTask(() => TaskQueueTestFixture.WriteSempaphore(semaphoreFile), TimeSpan.FromSeconds(intervalSeconds), "test"); taskScheduler.Tick(); File.Exists(semaphoreFile).Should().Be(false); // Confirm Scheduled Task Ran once Thread.Sleep(((intervalSeconds) * 1000) + 10); taskScheduler.Tick(); File.Exists(semaphoreFile).Should().Be(true); File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText); // Confirm Ran TWICE Thread.Sleep(((intervalSeconds) * 1000) + 10); taskScheduler.Tick(); File.Exists(semaphoreFile).Should().Be(true); File.ReadAllText(semaphoreFile).Should() .Be(TaskQueueTestFixture.SemaphoreText + TaskQueueTestFixture.SemaphoreText); }
public async Task ItExecutesTasksOnlyOnceWhenUsingMultipleConsumers(string taskType) { var semaphoreFile = Path.GetTempFileName(); File.Delete(semaphoreFile); File.Create(semaphoreFile).Close(); var intervalSeconds = 5; var taskQueue = TaskQueueTestFixture.UniqueRedisTaskQueue(); var schedulingTaskScheduler = new TaskScheduler(taskQueue); var taskSchedulers = new[] { new TaskScheduler(taskQueue), new TaskScheduler(taskQueue), new TaskScheduler(taskQueue), new TaskScheduler(taskQueue), }; if (taskType == "scheduled") { await schedulingTaskScheduler.AddScheduledTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromSeconds(intervalSeconds)); } if (taskType == "recurring") { await schedulingTaskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromSeconds(intervalSeconds), RandomTaskName); } Thread.Sleep(((intervalSeconds) * 1000) + 50); // Ran only once await Task.WhenAll( taskSchedulers.Select( taskScheduler => Task.Run(async() => { await taskScheduler.Tick(); await taskQueue.ExecuteNext(); }))); File.Exists(semaphoreFile).Should().Be(true); File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText); // Ran only twice (or once if scheduled) Thread.Sleep(((intervalSeconds) * 1000) + 50); await Task.WhenAll( taskSchedulers.Select( taskScheduler => Task.Run(async() => { await taskScheduler.Tick(); await taskQueue.ExecuteNext(); }))); if (taskType == "recurring") { File.ReadAllText(semaphoreFile).Should() .Be(TaskQueueTestFixture.SemaphoreText + TaskQueueTestFixture.SemaphoreText); } if (taskType == "scheduled") { File.ReadAllText(semaphoreFile).Should() .Be(TaskQueueTestFixture.SemaphoreText); } }
public async Task ItExecutesScheduledTasksOnlyOnce() { const int numberOfTasks = 1000; const int tasksPerTimeInterval = 25; const int timeInterval = 1000; const int numberOfSchedulerThreads = 4; TimeSpan promotionFrequency = TimeSpan.FromMilliseconds(100); ThreadPool.SetMinThreads(numberOfSchedulerThreads * 4, 200); var taskQueue = TaskQueueTestFixture.UniqueRedisTaskQueue(); var taskScheduler = new TaskScheduler(taskQueue, promotionFrequency); var canceled = false; var taskSchedulerTasks = new List <Task>(); var taskRunnerTasks = new List <Task>(); for (var s = 0; s < numberOfSchedulerThreads; ++s) { taskSchedulerTasks.Add(Task.Run(async() => { var inThreadTaskScheduler = new TaskScheduler(taskQueue); while (!canceled) { await inThreadTaskScheduler.Tick(forceRunPromotion: true); } })); taskRunnerTasks.Add(Task.Run(async() => { while (!canceled) { await taskQueue.ExecuteNext(); } })); } var tasks = new List <(ScheduledTask, string, string)>(); System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); for (var i = 0; i < numberOfTasks / tasksPerTimeInterval; ++i) { for (var k = 0; k < tasksPerTimeInterval; ++k) { var semaphoreFile = Path.GetTempFileName(); File.Delete(semaphoreFile); semaphoreFile = semaphoreFile + Guid.NewGuid().ToString(); var semaphoreValue = Guid.NewGuid().ToString(); var scheduledTask = await taskScheduler.AddScheduledTask( () => TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, semaphoreValue), TimeSpan.FromMilliseconds((i + 1) * timeInterval)); tasks.Add((scheduledTask, semaphoreFile, semaphoreValue)); } } _testOutputHelper.WriteLine(sw.ElapsedMilliseconds.ToString()); var precisionAllowanceFactorMs = promotionFrequency.TotalMilliseconds + 10; long now; for (var i = 0; i < numberOfTasks / tasksPerTimeInterval; ++i) { Thread.Sleep(timeInterval); // EACH TASK, 3 Cases // CASE 1: Scheduled Time should have run, allowing for precision loss // CASE 2: Scheduled Time should definitely not have run // CASE 3: Scheduled Time is past, but within precision allowance (may have run or not) foreach (var task in tasks) { now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); if (task.Item1.ScheduledUnixTimeMilliseconds <= (now - precisionAllowanceFactorMs)) { File.Exists(task.Item2).Should().BeTrue(); File.ReadAllText(task.Item2).Should().Be(task.Item3); } else if (task.Item1.ScheduledUnixTimeMilliseconds > now) { File.Exists(task.Item2).Should().BeFalse(); } } } Thread.Sleep((int)precisionAllowanceFactorMs); foreach (var task in tasks) { File.Exists(task.Item2).Should().BeTrue(); File.ReadAllText(task.Item2).Should().Be(task.Item3); } canceled = true; await Task.WhenAll(taskSchedulerTasks); await Task.WhenAll(taskRunnerTasks); }