/// <summary> /// Fetches all of the current known results for the Sent Notification and calculates the various totals /// as results. /// </summary> /// <param name="notificationId">The notification ID.</param> /// <param name="log">The logger.</param> /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns> public async Task <AggregatedSentNotificationDataResults> AggregateSentNotificationDataResultsAsync( string notificationId, ILogger log) { var partitionKeyFilter = TableQuery.GenerateFilterCondition( nameof(TableEntity.PartitionKey), QueryComparisons.Equal, notificationId); // The SentNotificationDataEntity.DeliveryStatus property's default value is null. // After finished processing a recipient, the send function sets the property to one of the following values, which indicates the delivery status. // Succeeded, // Failed, // RecipientNotFound, // Throttled, // etc. // The notNullStatusFilter finds out the delivery statuses for all the processed recipients. var notNullStatusFilter = TableQuery.GenerateFilterCondition( nameof(SentNotificationDataEntity.DeliveryStatus), QueryComparisons.NotEqual, "null"); // Create the complete query where: // PartitionKey eq notificationId AND DeliveryStatus ne null var completeFilter = TableQuery.CombineFilters(partitionKeyFilter, TableOperators.And, notNullStatusFilter); var query = new TableQuery <SentNotificationDataEntity>().Where(completeFilter); try { var aggregatedResults = new AggregatedSentNotificationDataResults(); TableContinuationToken currentContinuationToken = null; do { // Make the query to the data table and update the continuation token in order to continue to paginate the results. TableQuerySegment <SentNotificationDataEntity> resultSegment = await this.sentNotificationDataRepository.Table .ExecuteQuerySegmentedAsync <SentNotificationDataEntity>(query, currentContinuationToken); currentContinuationToken = resultSegment.ContinuationToken; // Aggregate the results. foreach (var sentNotification in resultSegment) { aggregatedResults.UpdateAggregatedResults(sentNotification); } }while (currentContinuationToken != null); return(aggregatedResults); } catch (Exception e) { var errorMessage = $"{e.GetType()}: {e.Message}"; log.LogError(e, $"ERROR: {errorMessage}"); throw; } }
/// <summary> /// Updates the notification totals with the given information and results. /// </summary> /// <param name="notificationId">The notification ID.</param> /// <param name="orchestrationStatus">The orchestration status of the notification.</param> /// <param name="shouldForceCompleteNotification">Flag to indicate if the notification should /// be forced to be marked as completed.</param> /// <param name="totalExpectedNotificationCount">The total expected count of notifications to be sent.</param> /// <param name="aggregatedSentNotificationDataResults">The current aggregated results for /// the sent notifications.</param> /// <param name="log">The logger.</param> /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns> public async Task <UpdateNotificationDataEntity> UpdateNotificationDataAsync( string notificationId, string orchestrationStatus, bool shouldForceCompleteNotification, int totalExpectedNotificationCount, AggregatedSentNotificationDataResults aggregatedSentNotificationDataResults, ILogger log) { try { var currentTotalNotificationCount = aggregatedSentNotificationDataResults.CurrentTotalNotificationCount; var succeededCount = aggregatedSentNotificationDataResults.SucceededCount; var failedCount = aggregatedSentNotificationDataResults.FailedCount; var throttledCount = aggregatedSentNotificationDataResults.ThrottledCount; var recipientNotFoundCount = aggregatedSentNotificationDataResults.RecipientNotFoundCount; var lastSentDate = aggregatedSentNotificationDataResults.LastSentDate; // Create the general update. var notificationDataEntityUpdate = new UpdateNotificationDataEntity { PartitionKey = NotificationDataTableNames.SentNotificationsPartition, RowKey = notificationId, Succeeded = succeededCount, Failed = failedCount, RecipientNotFound = recipientNotFoundCount, Throttled = throttledCount, }; if (orchestrationStatus.Equals(nameof(OrchestrationStatus.Terminated), StringComparison.InvariantCultureIgnoreCase) || orchestrationStatus.Equals(nameof(OrchestrationStatus.Completed), StringComparison.InvariantCultureIgnoreCase)) { if (currentTotalNotificationCount >= totalExpectedNotificationCount) { this.SetSentStatus(ref notificationDataEntityUpdate, lastSentDate); } else { var countDifference = totalExpectedNotificationCount - currentTotalNotificationCount; this.SetCanceledStatus(ref notificationDataEntityUpdate, countDifference); } } else // If it should be marked as complete, set the other values accordingly. if (currentTotalNotificationCount >= totalExpectedNotificationCount || shouldForceCompleteNotification) { if (currentTotalNotificationCount >= totalExpectedNotificationCount) { this.SetSentStatus(ref notificationDataEntityUpdate, lastSentDate); } else if (shouldForceCompleteNotification) { // If the message is being completed, not because all messages have been accounted for, // but because the trigger is coming from the delayed Service Bus message that ensures that the // notification will eventually be marked as complete, then update the unknown count of messages // not accounted for and update the sent date to the current time. var countDifference = totalExpectedNotificationCount - currentTotalNotificationCount; this.SetSentStatusWithUnknownCount(ref notificationDataEntityUpdate, countDifference); } } var operation = TableOperation.InsertOrMerge(notificationDataEntityUpdate); await this.notificationDataRepository.Table.ExecuteAsync(operation); return(notificationDataEntityUpdate); } catch (Exception e) { var errorMessage = $"{e.GetType()}: {e.Message}"; log.LogError(e, $"ERROR: {errorMessage}"); throw; } }
/// <summary> /// Updates the notification totals with the given information and results. /// </summary> /// <param name="notificationId">The notification ID.</param> /// <param name="shouldForceCompleteNotification">Flag to indicate if the notification should /// be forced to be marked as completed.</param> /// <param name="totalExpectedNotificationCount">The total expected count of notifications to be sent.</param> /// <param name="aggregatedSentNotificationDataResults">The current aggregated results for /// the sent notifications.</param> /// <param name="log">The logger.</param> /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns> public async Task <UpdateNotificationDataEntity> UpdateNotificationDataAsync( string notificationId, bool shouldForceCompleteNotification, int totalExpectedNotificationCount, AggregatedSentNotificationDataResults aggregatedSentNotificationDataResults, ILogger log) { try { var currentTotalNotificationCount = aggregatedSentNotificationDataResults.CurrentTotalNotificationCount; var succeededCount = aggregatedSentNotificationDataResults.SucceededCount; var failedCount = aggregatedSentNotificationDataResults.FailedCount; var throttledCount = aggregatedSentNotificationDataResults.ThrottledCount; var recipientNotFoundCount = aggregatedSentNotificationDataResults.RecipientNotFoundCount; var lastSentDate = aggregatedSentNotificationDataResults.LastSentDate; // Create the general update. var notificationDataEntityUpdate = new UpdateNotificationDataEntity { PartitionKey = NotificationDataTableNames.SentNotificationsPartition, RowKey = notificationId, Succeeded = succeededCount, Failed = failedCount, RecipientNotFound = recipientNotFoundCount, Throttled = throttledCount, }; // If it should be marked as complete, set the other values accordingly. if (currentTotalNotificationCount >= totalExpectedNotificationCount || shouldForceCompleteNotification) { // Update the status to Sent. notificationDataEntityUpdate.Status = NotificationStatus.Sent.ToString(); if (currentTotalNotificationCount >= totalExpectedNotificationCount) { // If the message is being completed because all messages have been accounted for, // then make sure the unknown count is 0 and update the sent date with the date // of the last sent message. notificationDataEntityUpdate.Unknown = 0; notificationDataEntityUpdate.SentDate = lastSentDate ?? DateTime.UtcNow; } else if (shouldForceCompleteNotification) { // If the message is being completed, not because all messages have been accounted for, // but because the trigger is coming from the delayed Service Bus message that ensures that the // notification will eventually be marked as complete, then update the unknown count of messages // not accounted for and update the sent date to the current time. var countDifference = totalExpectedNotificationCount - currentTotalNotificationCount; // This count must stay 0 or above. var unknownCount = countDifference >= 0 ? countDifference : 0; notificationDataEntityUpdate.Unknown = unknownCount; notificationDataEntityUpdate.SentDate = DateTime.UtcNow; } } var operation = TableOperation.InsertOrMerge(notificationDataEntityUpdate); await this.notificationDataRepository.Table.ExecuteAsync(operation); return(notificationDataEntityUpdate); } catch (Exception e) { var errorMessage = $"{e.GetType()}: {e.Message}"; log.LogError(e, $"ERROR: {errorMessage}"); throw; } }