public async Task ItDoesNotDelayScheduledTaskPromotionWhenRunningLongTasks() { var waitTime = 4000; var taskQueue = TaskQueueTestFixture.UniqueRedisTaskQueue(); var taskClient = new TaskClient(taskQueue); var semaphoreFile = Path.GetTempFileName(); File.Delete(semaphoreFile); File.Exists(semaphoreFile).Should().BeFalse(); await taskClient.TaskQueue.Enqueue(() => Wait(waitTime)); await taskClient.TaskScheduler.AddScheduledTask( () => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromMilliseconds(waitTime / 4)); var task = Task.Run(async() => await taskClient.Listen()); await Task.Delay(waitTime / 2); // Ensure we did not run the scheduled task File.Exists(semaphoreFile).Should().BeFalse(); var dequeuedScheduledTask = await taskQueue.Dequeue(); File.Exists(semaphoreFile).Should().BeFalse(); dequeuedScheduledTask.Should().NotBeNull(); dequeuedScheduledTask.MethodName.Should().Be(nameof(TaskQueueTestFixture.WriteSemaphore)); taskClient.CancelListen(); await task; }
public async Task ItAllowsForRecurringTaskCrontabSchedulesToBeChanged() { var taskName = Guid.NewGuid().ToString(); Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { var crontab = $"*/{IntervalSeconds} * * * * *"; TaskSchedulerTestHelpers.SynchronizeToCrontabNextStart(crontab); Thread.Sleep(10); await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), crontab, taskName); }; Func <string, TaskScheduler, Task> reconfigureRecurringTaskIntervalAction = async(semaphoreFile, taskScheduler) => { // Must synchronize to next start time or test becomes flaky var newCrontab = $"*/{IntervalSeconds*2} * * * * *"; TaskSchedulerTestHelpers.SynchronizeToCrontabNextStart(newCrontab); Thread.Sleep(10); await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), newCrontab, taskName); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerWritesSemaphoreTwiceAfterReconfiguringInterval( IntervalSeconds, configureSchedulerAction, reconfigureRecurringTaskIntervalAction); }
public async Task ItExecutesAScheduledTaskAtTheSpecifiedOffsetOnlyOnce() { Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { await taskScheduler.AddScheduledTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromSeconds(IntervalSeconds), RandomTaskName); }; await AssertTaskSchedulerWritesSemaphoreOnlyOnce(configureSchedulerAction); }
public async Task ItExecutesARecurringTaskAtTheSpecifiedCrontabInterval() { Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), $"*/{IntervalSeconds} * * * * *", RandomTaskName); }; await AssertTaskSchedulerWritesSemaphoreTwice(configureSchedulerAction); }
public async Task ItExecutesARecurringTaskAtTheSpecifiedInterval() { Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromSeconds(IntervalSeconds), RandomTaskName); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerWritesSemaphoreTwice( IntervalSeconds, configureSchedulerAction); }
public async Task ItExecutesAScheduledTaskAtTheSpecifiedDateTimeOnlyOnce() { Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { await taskScheduler.AddScheduledTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), DateTime.UtcNow + TimeSpan.FromSeconds(IntervalSeconds)); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerWritesSemaphoreOnlyOnce( IntervalSeconds, configureSchedulerAction); }
public async Task ItAllowsForRecurringTasksTaskInfoToBeChanged() { var taskName = Guid.NewGuid().ToString(); var taskQueue = TaskQueueTestFixture.UniqueRedisTaskQueue(); var taskScheduler = new TaskScheduler(taskQueue); var recurringTask = await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore("afile"), $"*/{IntervalSeconds} * * * * *", taskName); var fetchedRecurringTask = await taskScheduler.GetRecurringTask(recurringTask.TaskKey); fetchedRecurringTask.TaskInfo.MethodName.Should().Be("WriteSemaphore"); fetchedRecurringTask.Interval.Should().BeNull(); fetchedRecurringTask.Crontab.Should().Be($"*/{IntervalSeconds} * * * * *"); fetchedRecurringTask.TaskInfo.Args[0].Should().Be("afile"); // Different Argument await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore("bfile"), $"*/{IntervalSeconds} * * * * *", taskName); fetchedRecurringTask = await taskScheduler.GetRecurringTask(recurringTask.TaskKey); fetchedRecurringTask.TaskInfo.MethodName.Should().Be("WriteSemaphore"); fetchedRecurringTask.Interval.Should().BeNull(); fetchedRecurringTask.Crontab.Should().Be($"*/{IntervalSeconds} * * * * *"); fetchedRecurringTask.TaskInfo.Args[0].Should().Be("bfile"); // Different Interval await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore("bfile"), TimeSpan.FromSeconds(IntervalSeconds), taskName); fetchedRecurringTask = await taskScheduler.GetRecurringTask(recurringTask.TaskKey); fetchedRecurringTask.TaskInfo.MethodName.Should().Be("WriteSemaphore"); fetchedRecurringTask.Interval.Should().Be(TimeSpan.FromSeconds(IntervalSeconds)); fetchedRecurringTask.Crontab.Should().BeNull(); fetchedRecurringTask.TaskInfo.Args[0].Should().Be("bfile"); // Different Target Method await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphoreValue("bfile", "avalue"), TimeSpan.FromSeconds(IntervalSeconds), taskName); fetchedRecurringTask = await taskScheduler.GetRecurringTask(recurringTask.TaskKey); fetchedRecurringTask.TaskInfo.MethodName.Should().Be("WriteSemaphoreValue"); fetchedRecurringTask.Interval.Should().Be(TimeSpan.FromSeconds(IntervalSeconds)); fetchedRecurringTask.Crontab.Should().BeNull(); fetchedRecurringTask.TaskInfo.Args[0].Should().Be("bfile"); fetchedRecurringTask.TaskInfo.Args[1].Should().Be("avalue"); }
public async Task ItExecutesARecurringTaskAtTheSpecifiedCrontabInterval() { Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { var crontab = $"*/{IntervalSeconds} * * * * *"; TaskSchedulerTestHelpers.SynchronizeToCrontabNextStart(crontab); Thread.Sleep(10); await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), crontab, RandomTaskName); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerWritesSemaphoreTwice(IntervalSeconds, configureSchedulerAction); }
public async Task ItsTasksAreConsumedOnlyOnceByMultipleConsumers() { // Higher numbers here increase confidence var numberOfJobs = 16; var numberOfConsumers = 4; var sharedTaskQueueName = nameof(ItsTasksAreConsumedOnlyOnceByMultipleConsumers); var consumers = Enumerable.Range(0, numberOfConsumers) .Select(_ => new TaskQueueTestFixture(sharedTaskQueueName)).ToList(); var semaphoreFiles = new List <string>(); for (int i = 0; i < numberOfJobs; ++i) { var path = Path.GetTempFileName(); File.Delete(path); semaphoreFiles.Add(path); var sharedTaskQueue = consumers[0].TaskQueue; await sharedTaskQueue.Enqueue(() => TaskQueueTestFixture.WriteSemaphore(path)); } var tasks = new List <Task>(); // Purposely executing more times than the number of tasks we have // Specifically numberOfJobs * numberOfConsumers times. for (var i = 0; i < numberOfJobs; i += 1) { foreach (var consumer in consumers) { var task = Task.Run(() => consumer.TaskQueue.ExecuteNext()); tasks.Add(task); } } await Task.WhenAll(tasks); foreach (var semaphoreFile in semaphoreFiles) { File.ReadAllText(semaphoreFile).Should() .Be(TaskQueueTestFixture.SemaphoreText); } }
public async Task ItDoesNotOverwriteOriginalRecurringTaskWhenDuplicatesAreAdded() { var taskName = Guid.NewGuid().ToString(); var taskQueue = TaskQueueTestFixture.UniqueRedisTaskQueue(); var taskScheduler = new TaskScheduler(taskQueue); var originalRecurringTask = await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore("a"), TimeSpan.FromSeconds(IntervalSeconds), taskName); var duplicateRecurringTask = await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore("a"), TimeSpan.FromSeconds(IntervalSeconds), taskName); originalRecurringTask.Should().NotBeNull(); duplicateRecurringTask.Should().BeNull(); var recurringTask = await taskScheduler.GetRecurringTask(originalRecurringTask.TaskKey); recurringTask.StartTime.Should().Be(originalRecurringTask.StartTime); }
public async Task ItContinuesListeningWhenATaskThrowsAnException() { var waitTime = 5000; var taskQueue = TaskQueueTestFixture.UniqueRedisTaskQueue(); var taskClient = new TaskClient(taskQueue); var semaphoreFile = Path.GetTempFileName(); await taskClient.TaskQueue.Enqueue(() => Throw()); await taskClient.TaskQueue.Enqueue(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile)); var task = Task.Run(async() => await taskClient.Listen()); await Task.Delay(waitTime); taskClient.CancelListen(); await task; TaskQueueTestFixture.EnsureSemaphore(semaphoreFile); }
public async Task ItAllowsForScheduledTasksToBeCanceled() { var taskName = Guid.NewGuid().ToString(); ScheduledTask scheduledTask = null; Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { scheduledTask = await taskScheduler.AddScheduledTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), DateTime.UtcNow + TimeSpan.FromSeconds(IntervalSeconds)); }; Func <TaskScheduler, Task> cancelTaskAction = async(taskScheduler) => { (await taskScheduler.CancelScheduledTask(scheduledTask)).Should().BeTrue(); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerDoesNotWriteSemaphore( IntervalSeconds, configureSchedulerAction, cancelTaskAction); }
public async Task ItAllowsForRecurringTasksToBeCanceled() { var taskName = Guid.NewGuid().ToString(); RecurringTask recurringTask = null; Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { recurringTask = await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), $"*/{IntervalSeconds} * * * * *", taskName); }; Func <TaskScheduler, Task> cancelTaskAction = async(taskScheduler) => { (await taskScheduler.CancelRecurringTask(recurringTask)).Should().BeTrue(); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerDoesNotWriteSemaphore( IntervalSeconds, configureSchedulerAction, cancelTaskAction); }
public async Task ItAllowsForRecurringTaskTimespanSchedulesToBeChanged() { var taskName = Guid.NewGuid().ToString(); Func <string, TaskScheduler, Task> configureSchedulerAction = async(semaphoreFile, taskScheduler) => { await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromSeconds(IntervalSeconds), taskName); }; Func <string, TaskScheduler, Task> reconfigureRecurringTaskIntervalAction = async(semaphoreFile, taskScheduler) => { await taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile), TimeSpan.FromSeconds(IntervalSeconds * 2), taskName); }; await TaskSchedulerTestHelpers.AssertTaskSchedulerWritesSemaphoreTwiceAfterReconfiguringInterval( IntervalSeconds, configureSchedulerAction, reconfigureRecurringTaskIntervalAction); }
public async Task ItContinuesListeningWhenATaskThrowsAnException() { var waitTime = 5000; var taskClient = new TaskClient( TaskQueue.Redis(TaskQueueTestFixture.RedisConnectionString, nameof(ItContinuesListeningWhenATaskThrowsAnException)), restoreScheduleFromBackup: false); var semaphoreFile = Path.GetTempFileName(); await taskClient.TaskQueue.Enqueue(() => Throw()); await taskClient.TaskQueue.Enqueue(() => TaskQueueTestFixture.WriteSemaphore(semaphoreFile)); var task = Task.Run(async() => await taskClient.Listen()); await Task.Delay(waitTime); taskClient.CancelListen(); await task; TaskQueueTestFixture.EnsureSemaphore(semaphoreFile); }
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); } }