Ejemplo n.º 1
0
 public void ExceptionFunc(Exception exc, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, exc);
 }
Ejemplo n.º 2
0
 public void ArrayFunc2(int[] nums, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, string.Join(",", nums));
 }
Ejemplo n.º 3
0
 public void BoolFunc(bool num, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, num);
 }
Ejemplo n.º 4
0
 public void DoubleFunc(double num, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, num);
 }
Ejemplo n.º 5
0
 public void NullableTypeFunc(DateTime?dateTime, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSempaphoreValue(semaphoreFile, dateTime);
 }
Ejemplo n.º 6
0
 public void LongFunc(long num, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, num);
 }
Ejemplo n.º 7
0
 public void ObjectFunc(object num1, object num2, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, num2);
 }
Ejemplo n.º 8
0
 public void IntFunc(int num, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, num);
 }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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);
            }
        }
Ejemplo n.º 11
0
        public async Task ItExecutesCrontabRecurringTasksAccordingToTheirSchedules()
        {
            const int numberOfTasks              = 10;
            const int timeInterval               = 1000;
            const int testIntervals              = 10;
            const int numberOfSchedulerThreads   = 4;
            const int precisionAllowanceFactorMs = 800;

            ThreadPool.SetMinThreads(numberOfSchedulerThreads * 4, 200);

            var taskQueue     = TaskQueueTestFixture.UniqueRedisTaskQueue();
            var taskScheduler = new TaskScheduler(taskQueue);

            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 <(RecurringTask, string, string)>();

            for (var i = 0; i < numberOfTasks; ++i)
            {
                var semaphoreFile = Path.GetTempFileName();
                File.Delete(semaphoreFile);
                semaphoreFile = semaphoreFile + Guid.NewGuid().ToString();

                var semaphoreValue = Guid.NewGuid().ToString();

                var recurringTask = await taskScheduler.AddRecurringTask(
                    () => TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, semaphoreValue),
                    $"*/{timeInterval / 1000} * * * * *",
                    Guid.NewGuid().ToString());

                tasks.Add((recurringTask, semaphoreFile, semaphoreValue));
            }

            var synchronizationFactor =
                DateTime.UtcNow.ToUnixTimeMilliseconds() - DateTime.UtcNow.ToUnixTimeSeconds() * 1000;

            Thread.Sleep((int)synchronizationFactor + 100);

            for (var i = 0; i < testIntervals; ++i)
            {
                Thread.Sleep(timeInterval);

                foreach (var task in tasks)
                {
                    var diff = DateTime.UtcNow.ToUnixTimeMilliseconds()
                               - (task.Item1.FirstRunTime.ToUnixTimeMilliseconds() - timeInterval);
                    var elapsedIntervalsMax =
                        diff / timeInterval;

                    var elapsedIntervalsMin = (diff % timeInterval) <= precisionAllowanceFactorMs
                        ? elapsedIntervalsMax - 1
                        : elapsedIntervalsMax;

                    _testOutputHelper.WriteLine(diff.ToString());

                    elapsedIntervalsMax.Should().BeGreaterThan(i);

                    var expectedStringMax = "";
                    for (var e = 0; e < elapsedIntervalsMax; ++e)
                    {
                        expectedStringMax += task.Item3;
                    }

                    var expectedStringMin = "";
                    for (var e = 0; e < elapsedIntervalsMin; ++e)
                    {
                        expectedStringMin += task.Item3;
                    }

                    File.Exists(task.Item2).Should().BeTrue(elapsedIntervalsMax.ToString());

                    var fileText = File.ReadAllText(task.Item2);
                    if (fileText != expectedStringMax)
                    {
                        fileText.Should().Be(expectedStringMin);
                    }
                }
            }

            canceled = true;
            await Task.WhenAll(taskSchedulerTasks);

            await Task.WhenAll(taskRunnerTasks);
        }
Ejemplo n.º 12
0
        public void ItCapturesArgumentsPassedToEnqueuedDelegate()
        {
            var testFixture = new TaskQueueTestFixture(nameof(ItCapturesArgumentsPassedToEnqueuedDelegate));

            string variableToExtract = "extracted";

            var semaphoreFile = Path.GetTempFileName();
            var now           = DateTime.Now;
            var utcNow        = DateTime.UtcNow;

            Func <Expression <Action>, string, Tuple <Expression <Action>, string> > TC = (actionExp, str) =>
                                                                                          Tuple.Create <Expression <Action>, string>(
                actionExp,
                str);

            // Action to expected result
            var delgates = new Tuple <Expression <Action>, string>[]
            {
                // Integer Arguments
                TC(() => IntFunc(int.MaxValue, semaphoreFile), int.MaxValue.ToString()),
                TC(() => IntFunc(int.MinValue, semaphoreFile), int.MinValue.ToString()),
                TC(() => NullableIntFunc(null, semaphoreFile), "-1"),
                TC(() => NullableIntFunc(int.MinValue, semaphoreFile), int.MinValue.ToString()),
                TC(() => NullableIntFunc(int.MaxValue, semaphoreFile), int.MaxValue.ToString()),

                // Float Arguments
                TC(() => FloatFunc(float.MaxValue, semaphoreFile), float.MaxValue.ToString()),
                TC(() => FloatFunc(float.MinValue, semaphoreFile), float.MinValue.ToString()),

                // Double Arguments
                TC(() => DoubleFunc(double.MaxValue, semaphoreFile), double.MaxValue.ToString()),
                TC(() => DoubleFunc(double.MinValue, semaphoreFile), double.MinValue.ToString()),

                // Long Arguments
                TC(() => LongFunc(long.MaxValue, semaphoreFile), long.MaxValue.ToString()),
                TC(() => LongFunc(long.MinValue, semaphoreFile), long.MinValue.ToString()),

                TC(() => BoolFunc(true, semaphoreFile), true.ToString()),
                TC(() => BoolFunc(false, semaphoreFile), false.ToString()),

                TC(() => StringFunc("astring", semaphoreFile), "astring"),
                TC(() => StringFunc(variableToExtract, semaphoreFile), variableToExtract),

                TC(() => ObjectFunc(new TestDataHolder {
                    Value = "astring"
                }, semaphoreFile), "astring"),

                TC(() => DateTimeFunc(now, semaphoreFile), now.ToString()),
                TC(() => DateTimeFunc(utcNow, semaphoreFile), utcNow.ToString()),

                TC(() => NullableTypeFunc(null, semaphoreFile), "null"),
                TC(() => NullableTypeFunc(now, semaphoreFile), now.ToString()),
                TC(() => ArrayFunc1(new[] { "this", "string", "is" }, semaphoreFile), "this,string,is"),
                TC(() => ArrayFunc2(new[] { 1, 2, 3, 4 }, semaphoreFile), "1,2,3,4"),
                TC(() => ArrayFunc3(new int?[] { 1, 2, 3, null, 5 }, semaphoreFile), "1,2,3,null,5")
            };

            foreach (var tup in delgates)
            {
                var actionExpr     = tup.Item1;
                var expectedString = tup.Item2;

                File.Delete(semaphoreFile);

                testFixture.TaskQueue.Enqueue(actionExpr);
                testFixture.TaskQueue.ExecuteNext();

                File.ReadAllText(semaphoreFile).Should().Be(expectedString);
            }

            File.Delete(semaphoreFile);
        }
Ejemplo n.º 13
0
 public void FloatFunc(float num, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSempaphoreValue(semaphoreFile, num);
 }
Ejemplo n.º 14
0
        public async Task ItCapturesArgumentsPassedToEnqueuedDelegate()
        {
            var testFixture = new TaskQueueTestFixture(nameof(ItCapturesArgumentsPassedToEnqueuedDelegate));

            string variableToExtract = "extracted";

            var semaphoreFile = Path.GetTempFileName();
            var now           = DateTime.Now;
            var utcNow        = DateTime.UtcNow;

            Func <Expression <Action>, string, Tuple <Expression <Action>, string> > TC = (actionExp, str) =>
                                                                                          Tuple.Create <Expression <Action>, string>(
                actionExp,
                str);

            // Action to expected result
            var delgates = new Tuple <Expression <Action>, string>[]
            {
                // Exception Argument
                TC(() => ExceptionFunc(new Exception(), semaphoreFile), new Exception().ToString()),
                TC(() => ExceptionFunc(new CustomException(), semaphoreFile), new CustomException().ToString()),

                // Integer Arguments
                TC(() => IntFunc(int.MaxValue, semaphoreFile), int.MaxValue.ToString()),
                TC(() => IntFunc(int.MinValue, semaphoreFile), int.MinValue.ToString()),
                TC(() => NullableIntFunc(null, semaphoreFile), "-1"),
                TC(() => NullableIntFunc(int.MinValue, semaphoreFile), int.MinValue.ToString()),
                TC(() => NullableIntFunc(int.MaxValue, semaphoreFile), int.MaxValue.ToString()),

                // Float Arguments
                TC(() => FloatFunc(float.MaxValue, semaphoreFile), float.MaxValue.ToString()),
                TC(() => FloatFunc(float.MinValue, semaphoreFile), float.MinValue.ToString()),

                // Double Arguments
                TC(() => DoubleFunc(double.MaxValue, semaphoreFile), double.MaxValue.ToString()),
                TC(() => DoubleFunc(double.MinValue, semaphoreFile), double.MinValue.ToString()),

                // Long Arguments
                TC(() => LongFunc(long.MaxValue, semaphoreFile), long.MaxValue.ToString()),
                TC(() => LongFunc(long.MinValue, semaphoreFile), long.MinValue.ToString()),

                TC(() => BoolFunc(true, semaphoreFile), true.ToString()),
                TC(() => BoolFunc(false, semaphoreFile), false.ToString()),

                TC(() => StringFunc("astring", semaphoreFile), "astring"),
                TC(() => StringFunc(variableToExtract, semaphoreFile), variableToExtract),

                TC(() => ObjectFunc(new TestDataHolder {
                    Value = "astring"
                }, semaphoreFile), "astring"),

                TC(() => DateTimeFunc(now, semaphoreFile), now.ToString()),
                TC(() => DateTimeFunc(utcNow, semaphoreFile), utcNow.ToString()),

                TC(() => NullableTypeFunc(null, semaphoreFile), "null"),
                TC(() => NullableTypeFunc(now, semaphoreFile), now.ToString()),
                TC(() => ArrayFunc1(new[] { "this", "string", "is" }, semaphoreFile), "this,string,is"),
                TC(() => ArrayFunc2(new[] { 1, 2, 3, 4 }, semaphoreFile), "1,2,3,4"),
                TC(() => ArrayFunc3(new int?[] { 1, 2, 3, null, 5 }, semaphoreFile), "1,2,3,null,5"),

                // Awaiting inside the lambda is unnecessary, as the method is extracted and serialized.
#pragma warning disable 4014
                TC(() => AsyncFunc(semaphoreFile), "async"),
                TC(() => AsyncFuncThatReturnsString(semaphoreFile), "async")
#pragma warning restore 4014
            };


            foreach (var tup in delgates)
            {
                var actionExpr     = tup.Item1;
                var expectedString = tup.Item2;

                File.Delete(semaphoreFile);

                await testFixture.TaskQueue.Enqueue(actionExpr);

                await testFixture.TaskQueue.ExecuteNext();

                File.ReadAllText(semaphoreFile).Should().Be(expectedString);
            }

            File.Delete(semaphoreFile);
        }
Ejemplo n.º 15
0
 public void TypeFunc(Type typeArg, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, typeArg?.ToString() ?? "null");
 }
Ejemplo n.º 16
0
 public void DateTimeFunc(DateTime dateTime, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, dateTime);
 }
Ejemplo n.º 17
0
        internal static async Task AssertTaskSchedulerWritesSemaphoreTwiceAfterReconfiguringInterval(
            int intervalSeconds,
            Func <string, TaskScheduler, Task> configureSchedulerAction,
            Func <string, TaskScheduler, Task> reconfigureRecurringTaskIntervalAction)
        {
            var semaphoreFile = Path.GetTempFileName();

            File.Delete(semaphoreFile);

            var taskQueue     = TaskQueueTestFixture.UniqueRedisTaskQueue();
            var taskScheduler = new TaskScheduler(taskQueue);

            await configureSchedulerAction(semaphoreFile, taskScheduler);

            await taskScheduler.Tick();

            await taskQueue.ExecuteNext();

            File.Exists(semaphoreFile).Should().Be(false);

            // Confirm Scheduled Task Ran once
            Thread.Sleep((((intervalSeconds) * 1000) + 10));
            await taskScheduler.Tick();

            await taskQueue.ExecuteNext();

            File.Exists(semaphoreFile).Should().Be(true);
            File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText);

            // Confirm does not run before interval elapsed
            await taskScheduler.Tick();

            await taskQueue.ExecuteNext();

            File.Exists(semaphoreFile).Should().Be(true);
            File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText);

            // Reconfigure interval to 2 * IntervalSeconds
            await reconfigureRecurringTaskIntervalAction(semaphoreFile, taskScheduler);

            // Confirm does not run before interval elapsed
            await taskScheduler.Tick();

            await taskQueue.ExecuteNext();

            File.Exists(semaphoreFile).Should().Be(true);
            File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText);

            // Sleep previous interval & confirm does not run before interval elapsed
            Thread.Sleep((((intervalSeconds) * 1000) + 10));
            await taskScheduler.Tick();

            await taskQueue.ExecuteNext();

            File.Exists(semaphoreFile).Should().Be(true);
            File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText);

            // Confirm Ran Twice
            Thread.Sleep((((intervalSeconds) * 1000) + 10));
            await taskScheduler.Tick();

            await taskQueue.ExecuteNext();

            File.Exists(semaphoreFile).Should().Be(true);
            File.ReadAllText(semaphoreFile).Should()
            .Be(TaskQueueTestFixture.SemaphoreText + TaskQueueTestFixture.SemaphoreText);
        }
Ejemplo n.º 18
0
 public void NullableIntFunc(int?num, string semaphoreFile)
 {
     TaskQueueTestFixture.WriteSemaphoreValue(semaphoreFile, num ?? -1);
 }
Ejemplo n.º 19
0
        public void ItExecutesTasksOnlyOnceWhenUsingMultipleConsumers(string taskType)
        {
            var semaphoreFile = Path.GetTempFileName();

            File.Delete(semaphoreFile);
            File.Create(semaphoreFile).Close();

            var intervalSeconds = 5;

            var taskSchedulers = new[]
            {
                new TaskScheduler(TaskQueue.Redis(TaskQueueTestFixture.RedisConnectionString), restoreFromBackup: false),
                new TaskScheduler(TaskQueue.Redis(TaskQueueTestFixture.RedisConnectionString), restoreFromBackup: false),
                new TaskScheduler(TaskQueue.Redis(TaskQueueTestFixture.RedisConnectionString), restoreFromBackup: false),
                new TaskScheduler(TaskQueue.Redis(TaskQueueTestFixture.RedisConnectionString), restoreFromBackup: false)
            };

            foreach (var taskScheduler in taskSchedulers)
            {
                if (taskType == "scheduled")
                {
                    taskScheduler.AddScheduledTask(() => TaskQueueTestFixture.WriteSempaphore(semaphoreFile),
                                                   TimeSpan.FromSeconds(intervalSeconds), RandomTaskName);
                }

                if (taskType == "recurring")
                {
                    taskScheduler.AddRecurringTask(() => TaskQueueTestFixture.WriteSempaphore(semaphoreFile),
                                                   TimeSpan.FromSeconds(intervalSeconds), RandomTaskName);
                }
            }

            Thread.Sleep(((intervalSeconds) * 1000) + 1000);

            // Ran only once
            Task.WaitAll(
                taskSchedulers.Select(
                    taskScheduler =>
                    Task.Run(() => taskScheduler.Tick())).ToArray(), 1000);

            File.Exists(semaphoreFile).Should().Be(true);
            File.ReadAllText(semaphoreFile).Should().Be(TaskQueueTestFixture.SemaphoreText);


            // Ran only twice (or once if scheduled)
            Thread.Sleep(((intervalSeconds) * 1000) + 1000);
            Task.WaitAll(
                taskSchedulers.Select(
                    taskScheduler =>
                    Task.Run(() => taskScheduler.Tick())).ToArray(), 1000);

            if (taskType == "recurring")
            {
                File.ReadAllText(semaphoreFile).Should()
                .Be(TaskQueueTestFixture.SemaphoreText + TaskQueueTestFixture.SemaphoreText);
            }
            if (taskType == "scheduled")
            {
                File.ReadAllText(semaphoreFile).Should()
                .Be(TaskQueueTestFixture.SemaphoreText);
            }

            taskSchedulers[0].FlushBackupStorage();
        }