public void ProcessQueuedEmailNotificationsTestInvalidInput() { MeetingInviteController meetingInviteController = new MeetingInviteController(this.emailServiceManager.Object, this.logger); QueueNotificationItem queueNotificationItem = new QueueNotificationItem { NotificationIds = new string[] { Guid.NewGuid().ToString() } }; _ = Assert.ThrowsAsync <ArgumentException>(async() => await meetingInviteController.ProcessQueuedMeetingNotifications(null, queueNotificationItem)); _ = Assert.ThrowsAsync <ArgumentNullException>(async() => await meetingInviteController.ProcessQueuedMeetingNotifications("TestApp", null)); }
public void ProcessQueuedEmailNotificationsTestValidInput() { MeetingInviteController meetingInviteController = new MeetingInviteController(this.emailServiceManager.Object, this.logger); IList <NotificationResponse> responses = new List <NotificationResponse>(); string applicationName = "TestApp"; QueueNotificationItem queueNotificationItem = new QueueNotificationItem { NotificationIds = new string[] { Guid.NewGuid().ToString() } }; _ = this.emailServiceManager .Setup(emailServiceManager => emailServiceManager.ProcessMeetingNotifications(It.IsAny <string>(), It.IsAny <QueueNotificationItem>())) .Returns(Task.FromResult(responses)); Task <IList <NotificationResponse> > result = meetingInviteController.ProcessQueuedMeetingNotifications(applicationName, queueNotificationItem); Assert.AreEqual(result.Status.ToString(), "RanToCompletion"); this.emailServiceManager.Verify(mgr => mgr.ProcessMeetingNotifications(It.IsAny <string>(), It.IsAny <QueueNotificationItem>()), Times.Once); Assert.Pass(); }
/// <summary> /// Fetches the records for given notification ids and resends using MS Graph Provider. /// </summary> /// <param name="applicationName">Application associated with email notifications.</param> /// <param name="queueNotificationItem">Queue Notification Entity.</param> /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns> private async Task <IList <MeetingNotificationItemEntity> > ProcessMeetingNotificationsUsingProvider(string applicationName, QueueNotificationItem queueNotificationItem) { var traceProps = new Dictionary <string, string>(); traceProps[Constants.Application] = applicationName; IList <MeetingNotificationItemEntity> notSentEntities = new List <MeetingNotificationItemEntity>(); this.logger.TraceInformation($"Started {nameof(this.ProcessMeetingNotificationsUsingProvider)} method of {nameof(EmailServiceManager)}.", traceProps); List <string> notificationIds = queueNotificationItem.NotificationIds.ToList(); this.logger.TraceVerbose($"Started {nameof(this.emailNotificationRepository.GetMeetingNotificationItemEntities)} method in {nameof(EmailServiceManager)}.", traceProps); IList <MeetingNotificationItemEntity> notificationEntities = await this.emailNotificationRepository.GetMeetingNotificationItemEntities(notificationIds, applicationName).ConfigureAwait(false); this.logger.TraceVerbose($"Completed {nameof(this.emailNotificationRepository.GetMeetingNotificationItemEntities)} method in {nameof(EmailServiceManager)}.", traceProps); var notificationEntitiesToBeSkipped = new List <MeetingNotificationItemEntity>(); if (notificationEntities?.Count == 0) { throw new ArgumentException("No records found for the input notification ids.", nameof(queueNotificationItem)); } if (queueNotificationItem.IgnoreAlreadySent) { notificationEntitiesToBeSkipped = notificationEntities.Where(x => x.Status == NotificationItemStatus.Sent).ToList(); notificationEntities = notificationEntities.Where(x => x.Status != NotificationItemStatus.Sent).ToList(); } if (notificationEntities?.Count == 0) { return(notificationEntitiesToBeSkipped); } this.logger.TraceVerbose($"Started {nameof(this.ProcessMeetingNotificationsUsingProvider)} method in {nameof(EmailServiceManager)}.", traceProps); var retEntities = await this.ProcessMeetingNotificationEntities(applicationName, notificationEntities).ConfigureAwait(false); this.logger.TraceVerbose($"Completed {nameof(this.ProcessMeetingNotificationsUsingProvider)} method in {nameof(EmailServiceManager)}.", traceProps); retEntities = retEntities.Concat(notificationEntitiesToBeSkipped).ToList(); this.logger.TraceInformation($"Completed {nameof(this.ProcessNotificationsUsingProvider)} method of {nameof(EmailServiceManager)}.", traceProps); return(retEntities); }
/// <inheritdoc/> public async Task <IList <NotificationResponse> > ProcessMeetingNotifications(string applicationName, QueueNotificationItem queueNotificationItem) { var traceprops = new Dictionary <string, string>(); traceprops[Constants.Application] = applicationName; traceprops[Constants.MeetingNotificationCount] = queueNotificationItem?.NotificationIds.Length.ToString(CultureInfo.InvariantCulture); var stopwatch = new Stopwatch(); stopwatch.Start(); bool result = false; this.logger.WriteCustomEvent("ProcessMeetingNotifications Started", traceprops); try { this.logger.TraceInformation($"Started {nameof(this.ProcessMeetingNotifications)} method of {nameof(EmailServiceManager)}."); if (string.IsNullOrWhiteSpace(applicationName)) { throw new ArgumentException("Application Name cannot be null or empty.", nameof(applicationName)); } if (queueNotificationItem is null) { throw new ArgumentNullException(nameof(queueNotificationItem)); } IList <NotificationResponse> notificationResponses = new List <NotificationResponse>(); IList <MeetingNotificationItemEntity> notificationItemEntities = await this.ProcessMeetingNotificationsUsingProvider(applicationName, queueNotificationItem).ConfigureAwait(false); var responses = this.emailManager.NotificationEntitiesToResponse(notificationResponses, notificationItemEntities); this.logger.TraceInformation($"Finished {nameof(this.ProcessEmailNotifications)} method of {nameof(EmailServiceManager)}."); result = true; return(responses); } catch (Exception ex) { result = true; this.logger.WriteException(ex, traceprops); throw; } finally { stopwatch.Stop(); traceprops[Constants.Result] = result.ToString(CultureInfo.InvariantCulture); var metrics = new Dictionary <string, double>(); metrics[Constants.Duration] = stopwatch.ElapsedMilliseconds; this.logger.WriteCustomEvent("ProcessEmailNotifications Completed", traceprops, metrics); } }
public async Task Run([QueueTrigger("notifications-queue", Connection = "AzureWebJobsStorage")] CloudQueueMessage inputQueueItem) { var stopwatch = new Stopwatch(); stopwatch.Start(); var notifQueueItem = inputQueueItem.AsString; var traceProps = new Dictionary <string, string>(); traceProps["DequeueCount"] = inputQueueItem.DequeueCount.ToString(); traceProps["QueueMessageId"] = inputQueueItem.Id; traceProps["InsertionTime"] = inputQueueItem.InsertionTime.ToString(); this.logger.TraceInformation($"ProcessNotificationQueueItem started processing: {notifQueueItem}"); QueueNotificationItem queueNotificationItem = null; try { if (string.IsNullOrEmpty(notifQueueItem)) { throw new ArgumentException("message", nameof(notifQueueItem)); } queueNotificationItem = JsonConvert.DeserializeObject <QueueNotificationItem>(notifQueueItem); traceProps[NotificationService.Common.Constants.Application] = queueNotificationItem?.Application; traceProps[NotificationService.Common.Constants.CorrelationId] = queueNotificationItem?.CorrelationId; traceProps[NotificationService.Common.Constants.NotificationIds] = string.Join(',', queueNotificationItem?.NotificationIds); traceProps[NotificationService.Common.Constants.EmailNotificationCount] = string.Join(',', queueNotificationItem?.NotificationIds?.Length); traceProps[NotificationService.Common.Constants.NotificationType] = queueNotificationItem?.NotificationType.ToString(); this.logger.TraceInformation($"ProcessNotificationQueueItem. Notification Item: {notifQueueItem}", traceProps); this.logger.WriteCustomEvent("QueueEmailNotifications Started", traceProps); _ = traceProps.Remove(NotificationService.Common.Constants.NotificationIds); if (queueNotificationItem != null) { var notifType = queueNotificationItem.NotificationType == NotificationType.Mail ? Constants.EmailNotificationType : Constants.MeetingNotificationType; var stringContent = new StringContent(JsonConvert.SerializeObject(queueNotificationItem), Encoding.UTF8, Constants.JsonMIMEType); string notificationServiceEndpoint = this.configuration?[Constants.NotificationServiceEndpoint]; this.logger.TraceVerbose($"ProcessNotificationQueueItem fetching token to call notification service endpoint...", traceProps); this.logger.TraceInformation($"ProcessNotificationQueueItem calling notification service endpoint...", traceProps); var response = await this.httpClientHelper.PostAsync($"{notificationServiceEndpoint}/v1/{notifType}/process/{queueNotificationItem.Application}", stringContent); this.logger.TraceInformation($"ProcessNotificationQueueItem received response from notification service endpoint.", traceProps); if (!response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); this.logger.WriteException(new Exception($"An error occurred while processing {notifQueueItem} in ProcessNotificationQueueItem. Details: {content}."), traceProps); } } else { this.logger.WriteException(new Exception("Invalid queue item received by the processor."), traceProps); } } catch (TaskCanceledException ex) { this.logger.WriteException(ex, traceProps); // Ignoring this exception as notification service would process items but http has been timedout here. } catch (Exception ex) { string maxDequeueCountVal = Startup.MaxDequeueCount.Value; int maxDeqCount; if (int.TryParse(maxDequeueCountVal, out maxDeqCount)) { if (inputQueueItem.DequeueCount < maxDeqCount) { this.logger.WriteException(ex, traceProps); throw; } } this.logger.WriteException(ex, traceProps); await this.UpdateStatusOfNotificationItemsAsync(queueNotificationItem.NotificationIds, NotificationItemStatus.Failed, ex.Message); } finally { this.logger.TraceInformation($"ProcessNotificationQueueItem finished processing: {notifQueueItem}", traceProps); stopwatch.Stop(); var metrics = new Dictionary <string, double>(); metrics[NotificationService.Common.Constants.Duration] = stopwatch.ElapsedMilliseconds; this.logger.WriteCustomEvent("QueueEmailNotifications Completed", traceProps, metrics); } }
public async Task <IList <NotificationResponse> > ProcessQueuedMeetingNotifications(string applicationName, [FromBody] QueueNotificationItem queueNotificationItem) { var traceprops = new Dictionary <string, string>(); if (string.IsNullOrWhiteSpace(applicationName)) { throw new System.ArgumentException("Application Name cannot be null or empty.", nameof(applicationName)); } if (queueNotificationItem is null) { throw new System.ArgumentNullException(nameof(queueNotificationItem)); } if (queueNotificationItem.NotificationIds.Length == 0) { throw new ArgumentException("Notification IDs list should not be empty.", nameof(queueNotificationItem)); } traceprops[AIConstants.Application] = applicationName; traceprops[AIConstants.NotificationIds] = string.Join(',', queueNotificationItem.NotificationIds); traceprops[AIConstants.MeetingNotificationCount] = queueNotificationItem.NotificationIds.Length.ToString(CultureInfo.InvariantCulture); IList <NotificationResponse> notificationResponses; this.logger.TraceInformation($"Started {nameof(this.ProcessQueuedMeetingNotifications)} method of {nameof(EmailController)}.", traceprops); notificationResponses = await this.emailServiceManager.ProcessMeetingNotifications(applicationName, queueNotificationItem).ConfigureAwait(false); this.logger.TraceInformation($"Finished {nameof(this.ProcessQueuedMeetingNotifications)} method of {nameof(EmailController)}.", traceprops); return(notificationResponses); }
/// <summary> /// Fetches the records for given notification ids and resends using MS Graph Provider. /// </summary> /// <param name="applicationName">Application associated with email notifications.</param> /// <param name="queueNotificationItem">Queue Notification Entity.</param> /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns> private async Task <IList <EmailNotificationItemEntity> > ProcessNotificationsUsingProvider(string applicationName, QueueNotificationItem queueNotificationItem) { var traceProps = new Dictionary <string, string>(); traceProps[AIConstants.Application] = applicationName; IList <EmailNotificationItemEntity> notSentEntities = new List <EmailNotificationItemEntity>(); List <string> notificationIds = queueNotificationItem.NotificationIds.ToList(); traceProps[AIConstants.NotificationIds] = JsonConvert.SerializeObject(notificationIds); this.logger.TraceInformation($"Started {nameof(this.ProcessNotificationsUsingProvider)} method of {nameof(EmailServiceManager)}.", traceProps); IList <EmailNotificationItemEntity> notificationEntities = await this.emailNotificationRepository.GetEmailNotificationItemEntities(notificationIds, applicationName).ConfigureAwait(false); var notificationEntitiesToBeSkipped = new List <EmailNotificationItemEntity>(); if (notificationEntities.Count == 0) { #pragma warning disable CA2208 // Instantiate argument exceptions correctly throw new ArgumentException("No records found for the input notification ids.", nameof(notificationIds)); #pragma warning restore CA2208 // Instantiate argument exceptions correctly } if (queueNotificationItem.IgnoreAlreadySent) { notificationEntitiesToBeSkipped = notificationEntities.Where(x => x.Status == NotificationItemStatus.Sent).ToList(); notificationEntities = notificationEntities.Where(x => x.Status != NotificationItemStatus.Sent).ToList(); } if (notificationEntities.Count == 0) { return(notificationEntitiesToBeSkipped); } var retEntities = await this.ProcessNotificationEntities(applicationName, notificationEntities).ConfigureAwait(false); retEntities = retEntities.Concat(notificationEntitiesToBeSkipped).ToList(); this.logger.TraceInformation($"Completed {nameof(this.ProcessNotificationsUsingProvider)} method of {nameof(EmailServiceManager)}.", traceProps); return(retEntities); }