Пример #1
0
        public void GetNotificationIdFromBatchPartitionKey_InCorrectParameters_ShouldBeSuccess()
        {
            // Arrange
            string batchPartitionKey = "notificationId";

            // Act & Assert
            Assert.Throws <FormatException>(() => PartitionKeyUtility.GetNotificationIdFromBatchPartitionKey(batchPartitionKey));
        }
Пример #2
0
        public void GetBatchIdFromBatchPartitionKey_CorrectParameters_ShouldBeSuccess()
        {
            // Arrange
            string batchPartitionKey = "notificationId:1";
            var    expectedResult    = "1";

            // Act
            var result = PartitionKeyUtility.GetBatchIdFromBatchPartitionKey(batchPartitionKey);

            // Assert
            Assert.Equal(expectedResult, result);
        }
Пример #3
0
        public void CreateBatchPartitionKey_CorrectParameters_ShouldBeSuccess()
        {
            // Arrange
            string notificationId = "notificationId";
            int    batchIndex     = 1;
            var    expectedResult = $"{notificationId}:{batchIndex}";

            // Act
            var result = PartitionKeyUtility.CreateBatchPartitionKey(notificationId, batchIndex);

            // Assert
            Assert.Equal(expectedResult, result);
        }
Пример #4
0
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            var batchPartitionKey = context.GetInput <string>();
            var notificationId    = PartitionKeyUtility.GetNotificationIdFromBatchPartitionKey(batchPartitionKey);

            if (!context.IsReplaying)
            {
                log.LogInformation($"About to get pending recipients (with no conversation id in database).");
            }

            var recipients = await context.CallActivityWithRetryAsync <IEnumerable <SentNotificationDataEntity> >(
                FunctionNames.GetPendingRecipientsActivity,
                FunctionSettings.DefaultRetryOptions,
                batchPartitionKey);

            var count = recipients.ToList().Count;

            if (count == 0)
            {
                log.LogInformation("No pending recipients.");
                return;
            }

            if (!context.IsReplaying)
            {
                log.LogInformation($"About to create 1:1 conversations with {count} recipients.");
            }

            // Create conversation.
            var tasks = new List <Task>();

            foreach (var recipient in recipients)
            {
                // Update batch partition key to actual notification Id.
                // Because batch partition key is used only for batching data.
                // Actual state and data is stored against the notification id record in SentNotificationData Table.
                recipient.PartitionKey = notificationId;

                var task = context.CallActivityWithRetryAsync(
                    FunctionNames.TeamsConversationActivity,
                    FunctionSettings.DefaultRetryOptions,
                    (notificationId, batchPartitionKey, recipient));
                tasks.Add(task);
            }

            // Fan-out Fan-in.
            await Task.WhenAll(tasks);
        }
Пример #5
0
        public static async Task RunOrchestrator(
            [OrchestrationTrigger] IDurableOrchestrationContext context,
            ILogger log)
        {
            var batchPartitionKey = context.GetInput <string>();
            var notificationId    = PartitionKeyUtility.GetNotificationIdFromBatchPartitionKey(batchPartitionKey);
            var batchId           = PartitionKeyUtility.GetBatchIdFromBatchPartitionKey(batchPartitionKey);

            if (!context.IsReplaying)
            {
                log.LogInformation($"About to get recipients from batch {batchId}.");
            }

            var recipients = await context.CallActivityWithRetryAsync <IEnumerable <SentNotificationDataEntity> >(
                FunctionNames.GetRecipientsActivity,
                FunctionSettings.DefaultRetryOptions,
                batchPartitionKey);

            // Use the SendQueue's maximum number of messages in a batch request number because
            // the list is being broken into batches in order to be added to that queue.
            var batches = recipients.AsBatches(SendQueue.MaxNumberOfMessagesInBatchRequest).ToList();

            var totalBatchCount = batches.Count;

            if (!context.IsReplaying)
            {
                log.LogInformation($"About to process {totalBatchCount} batches.");
            }

            var tasks = new List <Task>();

            for (var batchIndex = 0; batchIndex < totalBatchCount; batchIndex++)
            {
                if (!context.IsReplaying)
                {
                    log.LogInformation($"About to process batch {batchIndex + 1} / {totalBatchCount}");
                }

                var task = context.CallActivityWithRetryAsync(
                    FunctionNames.SendBatchMessagesActivity,
                    FunctionSettings.DefaultRetryOptions,
                    (notificationId, batches[batchIndex]));

                tasks.Add(task);
            }

            // Fan-out Fan-in
            await Task.WhenAll(tasks);
        }
        public async Task BatchRecipients_AllParameters_ShouldBeSuccess()
        {
            // Arrange
            var    recipientService = this.GetRecipientsService();
            string notificationId   = "notificationId";
            var    recipients       = new List <SentNotificationDataEntity>()
            {
                new SentNotificationDataEntity()
                {
                    PartitionKey = notificationId, ConversationId = "conversationId"
                },
                new SentNotificationDataEntity()
                {
                    PartitionKey = notificationId, ConversationId = string.Empty
                },
                new SentNotificationDataEntity()
                {
                    PartitionKey = notificationId, ConversationId = "conversationId2"
                },
            };

            this.sentNotificationRepository
            .Setup(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >()))
            .Returns(Task.CompletedTask);

            var recipientBatches = recipients.AsBatches(Constants.MaximumNumberOfRecipientsInBatch).ToList();

            // Act
            RecipientsInfo recipientsInfo = default;
            Func <Task>    task           = async() => recipientsInfo = await recipientService.BatchRecipients(recipients);

            // Assert
            await task.Should().NotThrowAsync();

            Assert.Equal(recipientsInfo.TotalRecipientCount, recipients.Count);
            Assert.True(recipientsInfo.HasRecipientsPendingInstallation);
            Assert.Equal(notificationId, PartitionKeyUtility.GetNotificationIdFromBatchPartitionKey(recipientsInfo.BatchKeys.First()));
            this.sentNotificationRepository.Verify(x => x.BatchInsertOrMergeAsync(It.IsAny <IEnumerable <SentNotificationDataEntity> >()), Times.Exactly(recipientBatches.Count));
        }
        public async Task TeamsConversationRunOrchestratorTest()
        {
            // Arrange
            string batchPartitionKey = "notificationId:1";
            IEnumerable <SentNotificationDataEntity> recipients = new List <SentNotificationDataEntity>()
            {
                new SentNotificationDataEntity()
                {
                    ConversationId = "conversationId1", PartitionKey = batchPartitionKey
                },

                new SentNotificationDataEntity()
                {
                    ConversationId = "conversationId2", PartitionKey = batchPartitionKey
                },
            };

            var notificationId = PartitionKeyUtility.GetNotificationIdFromBatchPartitionKey(batchPartitionKey);

            this.mockContext
            .Setup(x => x.GetInput <string>())
            .Returns(batchPartitionKey);
            this.mockContext
            .Setup(x => x.CallActivityWithRetryAsync <IEnumerable <SentNotificationDataEntity> >(It.IsAny <string>(), It.IsAny <RetryOptions>(), It.IsAny <string>()))
            .ReturnsAsync(recipients);
            this.mockContext
            .Setup(x => x.CallActivityWithRetryAsync(It.IsAny <string>(), It.IsAny <RetryOptions>(), It.IsAny <object>()))
            .Returns(Task.CompletedTask);

            // Act
            Func <Task> task = async() => await TeamsConversationOrchestrator.RunOrchestrator(this.mockContext.Object, this.mockLogger.Object);

            // Assert
            await task.Should().NotThrowAsync <Exception>();

            this.mockContext.Verify(x => x.CallActivityWithRetryAsync <IEnumerable <SentNotificationDataEntity> >(It.Is <string>(x => x.Equals(FunctionNames.GetPendingRecipientsActivity)), It.IsAny <RetryOptions>(), It.IsAny <string>()), Times.Once);
            this.mockContext
            .Verify(x => x.CallActivityWithRetryAsync(It.Is <string>(x => x.Equals(FunctionNames.TeamsConversationActivity)), It.IsAny <RetryOptions>(), It.Is <(string notificationId, string batchPartitionKey, SentNotificationDataEntity recipients)>(x => x.recipients.PartitionKey.Equals(notificationId))), Times.Exactly(recipients.Count()));
        }
Пример #8
0
        /// <inheritdoc/>
        public async Task <RecipientsInfo> BatchRecipients(IEnumerable <SentNotificationDataEntity> recipients)
        {
            if (recipients == null)
            {
                throw new ArgumentNullException(nameof(IEnumerable <SentNotificationDataEntity>));
            }

            var notificationId = recipients.FirstOrDefault().PartitionKey;

            var recipientBatches = recipients.AsBatches(Constants.MaximumNumberOfRecipientsInBatch);
            var recipientInfo    = new RecipientsInfo(notificationId)
            {
                TotalRecipientCount = recipients.ToList().Count,
            };
            int batchIndex = 1;

            foreach (var recipientBatch in recipientBatches)
            {
                var recipientBatchList = recipientBatch.ToList();

                // Update PartitionKey to Batch Key
                recipientBatchList.ForEach(s =>
                {
                    s.PartitionKey = PartitionKeyUtility.CreateBatchPartitionKey(s.PartitionKey, batchIndex);

                    // Update if there is any recipient which has no conversation id.
                    recipientInfo.HasRecipientsPendingInstallation |= string.IsNullOrEmpty(s.ConversationId);
                });

                // Store.
                await this.sentNotificationDataRepository.BatchInsertOrMergeAsync(recipientBatch);

                recipientInfo.BatchKeys.Add(recipientBatch.FirstOrDefault().PartitionKey);
                batchIndex++;
            }

            return(recipientInfo);
        }