public async Task Test_EnqueueDoesNotChangePeekResult_SingleConsumer()
        {
            int         futureTicks = 1;
            IQueuedTask peekTask    = null,
                        rePeekTask  = null;

            string taskType = typeof(SampleTaskPayload)
                              .FullName;

            PostgreSqlTaskQueueProducer taskQueueProducer = CreateTaskQueueProducer(() => mDataSource
                                                                                    .LastPostedAt
                                                                                    .AddTicks(1));

            PostgreSqlTaskQueueInfo taskQueueInfo = CreateTaskQueueInfo(() => mDataSource
                                                                        .LastPostedAt
                                                                        .AddTicks(futureTicks++));

            peekTask = await taskQueueInfo.PeekAsync();

            Assert.NotNull(peekTask);

            await taskQueueProducer.EnqueueAsync(payload : new SampleTaskPayload(100),
                                                 source : nameof(Test_EnqueueDoesNotChangePeekResult_SingleConsumer),
                                                 priority : 0);

            rePeekTask = await taskQueueInfo.PeekAsync();

            Assert.NotNull(rePeekTask);

            //Placing a new element in a queue occurs at its end,
            //  so peeking must not be affected
            //  if no other operation occurs
            Assert.AreEqual(peekTask.Id,
                            rePeekTask.Id);
        }
Beispiel #2
0
        public async Task Test_CanEnqueue_NewTask_Serial()
        {
            Faker faker =
                new Faker();

            ManualResetEvent notificationWaitHandle =
                new ManualResetEvent(false);

            DateTimeOffset postedAt = mDataSource.LastPostedAt
                                      .AddTicks(1);

            PostgreSqlTaskQueueProducer taskQueueProducer =
                CreateTaskQueueProducer(() => postedAt);

            EventHandler <ClearForDequeueEventArgs> handleClearForDequeue = (s, e) =>
            {
                if (e.Reason == ClearForDequeReason.NewTaskPostedNotificationReceived)
                {
                    notificationWaitHandle.Set();
                }
            };

            using (PostgreSqlTaskQueueConsumer taskQueueConsumer =
                       CreateTaskQueueConsumer(() => postedAt))
            {
                taskQueueConsumer.ClearForDequeue +=
                    handleClearForDequeue;

                await taskQueueConsumer
                .StartReceivingNewTaskUpdatesAsync();

                Assert.IsTrue(taskQueueConsumer
                              .IsReceivingNewTaskUpdates);

                //Enqueue task and check result
                IQueuedTask queuedTask = await taskQueueProducer
                                         .EnqueueAsync(payload : new SampleTaskPayload(100),
                                                       source : nameof(Test_CanEnqueue_NewTask_Serial),
                                                       priority : faker.Random.Int(1, 100));

                Assert.NotNull(queuedTask);
                await Assert_ResultAddedOrUpdatedCorrectly(queuedTask);

                notificationWaitHandle.WaitOne();

                await taskQueueConsumer
                .StopReceivingNewTaskUpdatesAsync();

                Assert.IsFalse(taskQueueConsumer
                               .IsReceivingNewTaskUpdates);

                taskQueueConsumer.ClearForDequeue -=
                    handleClearForDequeue;
            }
        }
        public async Task Test_StatsAreUpdatedCorrectly_AfterEnqueue_RepostExistingTask()
        {
            Faker faker =
                new Faker();

            DateTimeOffset postedAt = mDataSource.LastPostedAt
                                      .AddTicks(1);

            PostgreSqlTaskQueueProducer taskQueueProducer =
                CreateTaskQueueProducer(() => postedAt);

            PostgreSqlTaskQueueInfo taskQueueInfo =
                CreateTaskQueueInfo(() => postedAt);

            foreach (IQueuedTaskToken token in mDataSource.CanBeRepostedSeededTaskTokens)
            {
                using (TaskQueueMetricsDiffChecker diff = new TaskQueueMetricsDiffChecker(async()
                                                                                          => await taskQueueInfo.ComputeMetricsAsync()))
                {
                    QueuedTaskStatus prevStatus = token
                                                  .LastQueuedTaskResult
                                                  .Status;

                    await diff.CaptureInitialMetricsAsync();

                    QueuedTaskInfo repostTaskInfo = new QueuedTaskInfo()
                    {
                        Id            = token.DequeuedTask.Id,
                        Priority      = faker.Random.Int(1, 100),
                        Payload       = token.DequeuedTask.Payload,
                        Source        = nameof(Test_StatsAreUpdatedCorrectly_AfterEnqueue_RepostExistingTask),
                        Type          = token.DequeuedTask.Type,
                        LockedUntilTs = postedAt.AddMinutes(faker.Random.Long(1000, 10000))
                    };

                    //Remove task record from DB - only dequeued tasks get reposted
                    await mDataSource.RemoveQueuedTaskFromDbByIdAsync(token
                                                                      .DequeuedTask
                                                                      .Id);

                    await taskQueueProducer.EnqueueAsync(repostTaskInfo);

                    await diff.CaptureNewMetricsAndAssertCorrectDiff(delta : new TaskQueueMetrics(
                                                                         totalUnprocessed: prevStatus != QueuedTaskStatus.Unprocessed ? 1 : 0,
                                                                         totalProcessing: prevStatus == QueuedTaskStatus.Processing ? -1 : 0,
                                                                         totalErrored: prevStatus == QueuedTaskStatus.Error ? -1 : 0,
                                                                         totalFaulted: prevStatus == QueuedTaskStatus.Faulted ? -1 : 0,
                                                                         totalFataled: prevStatus == QueuedTaskStatus.Fatal ? -1 : 0,
                                                                         totalProcessed: prevStatus == QueuedTaskStatus.Processed ? -1 : 0));
                }
            }
        }
Beispiel #4
0
        public StandardTaskEngine(TaskEngineOptions engineOptions,
                                  TaskQueueOptions producerAndResultOptions,
                                  TaskQueueConsumerOptions consumerOptions,
                                  ITaskExecutorRegistry executorRegistry,
                                  IExecutionPerformanceMonitorWriter executionPerfMonWriter,
                                  ITimestampProvider timestampProvider)
        {
            if (engineOptions == null)
            {
                throw new ArgumentNullException(nameof(engineOptions));
            }

            if (consumerOptions == null)
            {
                throw new ArgumentNullException(nameof(consumerOptions));
            }

            if (producerAndResultOptions == null)
            {
                throw new ArgumentNullException(nameof(producerAndResultOptions));
            }

            mExecutorRegistry = executorRegistry
                                ?? throw new ArgumentNullException(nameof(executorRegistry));

            mExecutionPerfMonWriter = executionPerfMonWriter
                                      ?? throw new ArgumentNullException(nameof(executionPerfMonWriter));

            mExecutionPerfMon  = new StandardExecutionPerformanceMonitor();
            mTaskQueueConsumer = new PostgreSqlTaskQueueConsumer(consumerOptions,
                                                                 timestampProvider);
            mTaskQueueProducer = new PostgreSqlTaskQueueProducer(producerAndResultOptions,
                                                                 timestampProvider);

            mTaskResultQueue = new PostgreSqlTaskResultQueue(producerAndResultOptions);

            mTaskBuffer = new StandardTaskBuffer(engineOptions.WorkerCount);
            mTaskPoller = new StandardTaskPoller(engineOptions.TaskProcessingOptions,
                                                 mTaskQueueConsumer,
                                                 mTaskBuffer);

            mOptions = engineOptions;
        }
Beispiel #5
0
        public ITaskEngine BuildTaskEngine()
        {
            ITaskExecutorRegistry executorRegistry = mTaskExecutorRegistrySetup
                                                     .BuildTaskExecutorRegistry();

            IExecutionPerformanceMonitorWriter executionPerfMonWriter = mPerformanceMonitorWriterSetup
                                                                        .BuildWriter();

            ITimestampProvider timestampProvider =
                new UtcNowTimestampProvider();

            TaskQueueConsumerOptions consumerOptions = mTaskQueueConsumerSetup
                                                       .BuildOptions();

            TaskQueueOptions producerOptions = mTaskQueueProducerSetup
                                               .BuildOptions();

            StakhanoviseLogManager.Provider = mLoggingProvider
                                              ?? new NoOpLoggingProvider();

            ITaskQueueProducer taskQueueProducer = new PostgreSqlTaskQueueProducer(producerOptions,
                                                                                   timestampProvider);

            ITaskQueueInfo taskQueueInfo = new PostgreSqlTaskQueueInfo(mTaskQueueInfoSetup.BuildOptions(),
                                                                       timestampProvider);

            if (mRegisterOwnDependencies)
            {
                executorRegistry.LoadDependencies(new Dictionary <Type, object>()
                {
                    { typeof(ITaskQueueProducer),
                      taskQueueProducer },
                    { typeof(ITaskQueueInfo),
                      taskQueueInfo }
                });
            }

            return(mTaskEngineSetup.BuildTaskEngine(consumerOptions,
                                                    producerOptions,
                                                    executorRegistry,
                                                    executionPerfMonWriter,
                                                    timestampProvider));
        }
        public async Task Test_StatsAreUpdatedCorrectly_AfterEnqueue_NewTask()
        {
            Faker faker =
                new Faker();

            DateTimeOffset postedAt = mDataSource.LastPostedAt
                                      .AddTicks(1);

            PostgreSqlTaskQueueProducer taskQueueProducer =
                CreateTaskQueueProducer(() => postedAt);

            PostgreSqlTaskQueueInfo taskQueueInfo =
                CreateTaskQueueInfo(() => postedAt);

            using (PostgreSqlTaskQueueConsumer taskQueueConsumer =
                       CreateTaskQueueConsumer(() => postedAt))
                using (TaskQueueMetricsDiffChecker diff = new TaskQueueMetricsDiffChecker(async()
                                                                                          => await taskQueueInfo.ComputeMetricsAsync()))
                {
                    await taskQueueConsumer.StartReceivingNewTaskUpdatesAsync();

                    Assert.IsTrue(taskQueueConsumer.IsReceivingNewTaskUpdates);

                    //Capture previous metrics
                    await diff.CaptureInitialMetricsAsync();

                    await taskQueueProducer.EnqueueAsync(payload : new SampleTaskPayload(100),
                                                         source : nameof(Test_StatsAreUpdatedCorrectly_AfterEnqueue_NewTask),
                                                         priority : faker.Random.Int(1, 100));

                    //Check that new metrics differ from the previous ones as expected
                    await diff.CaptureNewMetricsAndAssertCorrectDiff(delta : new TaskQueueMetrics(
                                                                         totalUnprocessed: 1,
                                                                         totalProcessing: 0,
                                                                         totalErrored: 0,
                                                                         totalFaulted: 0,
                                                                         totalFataled: 0,
                                                                         totalProcessed: 0));
                }
        }
Beispiel #7
0
        public async Task Test_CanEnqueue_RepostExistingTask_Serial()
        {
            Faker faker =
                new Faker();

            DateTimeOffset postedAt = mDataSource.LastPostedAt
                                      .AddSeconds(1);

            PostgreSqlTaskQueueProducer taskQueueProducer =
                CreateTaskQueueProducer(() => postedAt);

            foreach (IQueuedTaskToken token in mDataSource.CanBeRepostedSeededTaskTokens)
            {
                QueuedTaskInfo repostTaskInfo = new QueuedTaskInfo()
                {
                    Id            = token.DequeuedTask.Id,
                    Priority      = faker.Random.Int(1, 100),
                    Payload       = token.DequeuedTask.Payload,
                    Source        = nameof(Test_CanEnqueue_RepostExistingTask_Serial),
                    Type          = token.DequeuedTask.Type,
                    LockedUntilTs = postedAt.AddMilliseconds(faker.Random.Long(1000, 10000))
                };

                //Remove task record from DB - only dequeued tasks get reposted
                await mDataSource.RemoveQueuedTaskFromDbByIdAsync(token
                                                                  .DequeuedTask
                                                                  .Id);

                //Enqueue task and check result
                IQueuedTask requeuedTask = await taskQueueProducer
                                           .EnqueueAsync(repostTaskInfo);

                Assert.NotNull(requeuedTask);
                await Assert_ResultAddedOrUpdatedCorrectly(requeuedTask);
            }
        }
Beispiel #8
0
        public async Task Test_CanEnqueue_NewTask_ParallelProducers(int nProducers)
        {
            Faker faker =
                new Faker();

            CountdownEvent notificationWaitHandle =
                new CountdownEvent(nProducers);

            DateTimeOffset postedAt = mDataSource.LastPostedAt
                                      .AddTicks(1);

            PostgreSqlTaskQueueProducer taskQueueProducer =
                CreateTaskQueueProducer(() => postedAt);

            EventHandler <ClearForDequeueEventArgs> handleClearForDequeue = (s, e) =>
            {
                if (e.Reason == ClearForDequeReason.NewTaskPostedNotificationReceived)
                {
                    notificationWaitHandle.Signal();
                }
            };

            Task[] producers = new Task[nProducers];

            using (PostgreSqlTaskQueueConsumer taskQueueConsumer =
                       CreateTaskQueueConsumer(() => postedAt))
            {
                taskQueueConsumer.ClearForDequeue +=
                    handleClearForDequeue;

                await taskQueueConsumer
                .StartReceivingNewTaskUpdatesAsync();

                Assert.IsTrue(taskQueueConsumer
                              .IsReceivingNewTaskUpdates);

                for (int i = 0; i < nProducers; i++)
                {
                    producers[i] = Task.Run(async() =>
                    {
                        //Enqueue task and check result
                        IQueuedTask queuedTask = await taskQueueProducer
                                                 .EnqueueAsync(payload: new SampleTaskPayload(100),
                                                               source: nameof(Test_CanEnqueue_NewTask_ParallelProducers),
                                                               priority: faker.Random.Int(1, 100));

                        Assert.NotNull(queuedTask);
                        await Assert_ResultAddedOrUpdatedCorrectly(queuedTask);
                    });
                }

                notificationWaitHandle.Wait();

                await taskQueueConsumer
                .StopReceivingNewTaskUpdatesAsync();

                Assert.IsFalse(taskQueueConsumer
                               .IsReceivingNewTaskUpdates);

                taskQueueConsumer.ClearForDequeue -=
                    handleClearForDequeue;
            }
        }