using System;
public class Program
{
public static void Main()
Console.WriteLine("Hello World");
}
/*
using Autofac;
using Hangfire;
using Newtonsoft.Json;
using PSE.Outage.Core;
using PSE.Outage.Data;
using PSE.Outage.Data.CassandraModels;
using PSE.Outage.Notifications.Notification;
using StackExchange.Redis;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon.SQS;
using Amazon.SQS.Model;
using PSE.Outage.Data.RedisModels;
using Message = PSE.Outage.Data.Message;
namespace PSE.Outage.Notifications
public class QueueProcessor : IQueueProcessor
#region variables
private static readonly IAppLogger<NotificationsEventId> _logger = Utils.GetAppLogger<NotificationsEventId>();
const double MaxRunCount = 5;// the number of retries for a specific task
private readonly IDatabaseAsync _db;
private readonly IQueueProvider _queueProvider;
#endregion
public QueueProcessor(IDatabaseAsync redisDb, IQueueProvider queueProvider)
_db = redisDb;
_queueProvider = queueProvider;
public async Task<Dictionary<TaskMessage.TaskType, TaskProcessingSummary>> Process(QueueInfo queueInfo,
TimeSpan pollingInterval,
IJobCancellationToken ct)
Dictionary<TaskMessage.TaskType, TaskProcessingSummary> summary =
new Dictionary<TaskMessage.TaskType, TaskProcessingSummary>();
while (!ct.ShutdownToken.IsCancellationRequested)
ct.ThrowIfCancellationRequested();
try
var receiveMessageResponse = await _queueProvider.EnsureDequeue<ReceiveMessageResponse>(queueInfo.QueueName).ConfigureAwait(false);
if (receiveMessageResponse == null) throw new ArgumentNullException(nameof(receiveMessageResponse));
if (receiveMessageResponse.Messages == null) throw new ArgumentNullException(nameof(receiveMessageResponse.Messages));
if (!receiveMessageResponse.Messages.Any()) continue;
foreach (var taskItem in receiveMessageResponse.Messages)
if (string.IsNullOrWhiteSpace(taskItem.Body))
_logger.Debug(NotificationsEventId.Default, null, $"Process- taskItem is null. Qname: {queueInfo.QueueName}");
await Task.Delay(pollingInterval).ConfigureAwait(false);
// TODO: this approach is inefficient because all tasks uselessly poll Redis when the queue is empty
else
_logger.Info(NotificationsEventId.Default, null, $"Process- before ProcessTaskItem: {taskItem.Body} - Qname: {queueInfo.QueueName}");
await ProcessTaskItem(taskItem.Body, queueInfo, summary).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"Process- after ProcessTaskItem: {taskItem} - Qname: {queueInfo.QueueName}");
catch (Exception ex)
_logger.ErrorException(NotificationsEventId.UnhandledQueueprocessorError, ex, null, $"An exception was caught while processing the queue {queueInfo.QueueName}. Exception message: { ex.Message } ");
_logger.Debug(NotificationsEventId.Default, null, $"Process end- exited while loop");
return summary;
private async Task ProcessTaskItem(string taskItem, QueueInfo queueInfo, Dictionary<TaskMessage.TaskType, TaskProcessingSummary> summary)
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....1");
TaskMessage taskObj = (TaskMessage)JsonConvert.DeserializeObject(taskItem, typeof(TaskMessage));
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....2: NotifyId: {taskObj.TaskId}");
#region check for older notifications
var outageNotification = (NotificationTask)JsonConvert.DeserializeObject(taskObj.Message, typeof(NotificationTask));
var nightModeHours = await Data.Common.GetNightModeHours().ConfigureAwait(false);
if (outageNotification != null && nightModeHours.HasValue)
var ts = DateTimeOffset.UtcNow.Subtract(outageNotification.InsertTime);
if (ts.TotalHours > nightModeHours.Value)
// log and suppress this notification object
// since it is older past night mode duration
_logger.Info(NotificationsEventId.NotificationSuppressed, () => new { taskObj.TaskId, outageNotification.NotificationId }, JsonConvert.SerializeObject(outageNotification));
return;
double runCount = await _db.HashIncrementAsync(queueInfo.TrackingHashName, RunCountKey(taskObj)).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....3: runCount: {runCount}");
TaskProcessingSummary t;
if (!summary.TryGetValue(taskObj.Type, out t))
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....summary.TryGetValue = FALSE");
t = new TaskProcessingSummary { TaskType = taskObj.Type };
summary.Add(t.TaskType, t);
if (runCount <= MaxRunCount)
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....before ProcessTaskMessage: NotifyId: {taskObj.TaskId}");
bool success = await ProcessTaskMessage(taskObj, queueInfo.TrackingHashName).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....after ProcessTaskMessage: NotifyId: {taskObj.TaskId} success: {success}");
if (success)
t.SuccessCount++;
t.RetryCount++;
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....SuccessCount: {t.SuccessCount} RetryCount: {t.RetryCount}");
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskItem....in else: NotifyId: {taskObj.TaskId}");
t.MaxRunCountExceeded++;
_logger.Error(NotificationsEventId.MaxRunForSingletaskError, null, "Outage Notification task {0} has exceeded the maximum run count of {1}", taskObj.TaskId, MaxRunCount);
private async Task<bool> ProcessTaskMessage(TaskMessage taskObj, string trackingHashName)
_logger.Debug(NotificationsEventId.Default, null, "ProcessTaskMessage....1");
bool taskCompleted = false;
await _db.HashSetAsync(trackingHashName, StartTimeKey(taskObj), DateTimeOffset.UtcNow.ToString()).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, "ProcessTaskMessage....2");
switch (taskObj.Type)
case TaskMessage.TaskType.Email:
_logger.Debug(NotificationsEventId.Default, null, "ProcessTaskMessage....before Send Email");
taskCompleted = await SendEmail(taskObj.Message).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, "ProcessTaskMessage....after Send Email");
catch (Exception e)
taskCompleted = false;
_logger.ErrorException(NotificationsEventId.ExceptionForTaskTypeEmail, e, () => new { taskObj.Message });
break;
case TaskMessage.TaskType.SMS:
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskMessage....before Send SMS for task: {taskObj.TaskId}");
taskCompleted = await SendSMS(taskObj.Message).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskMessage....after Send SMS for task: {taskObj.TaskId}");
_logger.ErrorException(NotificationsEventId.ExceptionForTaskTypeSms, e, () => new { taskObj.Message });
case TaskMessage.TaskType.Voice:
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskMessage....before Send Voice for task: {taskObj.TaskId}");
taskCompleted = await SendVoice(taskObj.Message).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"ProcessTaskMessage....after Send Voice for task: {taskObj.TaskId}");
_logger.ErrorException(NotificationsEventId.ExceptionForTaskTypeVoice, e, () => new { taskObj.Message });
default:
_logger.Error(NotificationsEventId.RedisQueueUnKnownTaskError, null, "Unknown task type for task {0}", taskObj.TaskId);
_logger.ErrorException(NotificationsEventId.RedisQueueTaskError, ex, null, "An exception was caught while processing task {0}", taskObj.TaskId);
_logger.Debug(NotificationsEventId.Default, null,
taskCompleted
? $"ProcessTaskMessage....task Completed for task: {taskObj.TaskId}"
: $"ProcessTaskMessage....task NOT Completed for task: {taskObj.TaskId}");
return taskCompleted;
/// <summary>
/// Initiates Voice calls to twlio
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
private async Task<bool> SendVoice(string message)
_logger.Debug(NotificationsEventId.Default, null, $"SendVoice- message {message}");
if (string.IsNullOrWhiteSpace(message)) throw new ArgumentNullException(nameof(message));
bool result = false;
//Deserialize the JSON SMS object and compose SMS and send to SMS Provider
NotificationTask voiceTask = (NotificationTask)JsonConvert.DeserializeObject(message, typeof(NotificationTask));
_logger.Debug(NotificationsEventId.Default, null, $"SendVoice- voice deserialize: -notifyid: {voiceTask.NotificationId}");
var messages = MapSMSTaskToMessage(voiceTask);
_logger.Debug(NotificationsEventId.Default, null, $"SendVoice- after MapSMSTaskToMessage");
using (var scope = Bootstrap.Container.BeginLifetimeScope())
//Set voice task info in redis for the specific notificationid
_logger.Debug(NotificationsEventId.Default, null, $"inserting notification task to redis voice: {message}");
await SetRedisVoiceOutage(voiceTask).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"SendVoice- after SetRedisVoiceOutage -notifyid: {voiceTask.NotificationId}");
IEngine _engine = scope.Resolve<IEngine>();
IBridge _bridge = _engine.BridgeInstance(PreferenceKind.Voice, messages);
NotifyBase _sendVoice = scope.Resolve<VoiceNotifier>(new TypedParameter(typeof(IBridge), _bridge));
result = await _sendVoice.Notify().ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"SendVoice- after voice send: {result} -notifyid: {voiceTask.NotificationId}");
return result;
private async Task<bool> SendSMS(string message)
_logger.Debug(NotificationsEventId.Default, null, $"SendSms- message {message}");
NotificationTask smsTask = (NotificationTask)JsonConvert.DeserializeObject(message, typeof(NotificationTask));
_logger.Debug(NotificationsEventId.Default, null, $"SendSms- sms deserialize: -notifyid: {smsTask.NotificationId}");
var messages = MapSMSTaskToMessage(smsTask);
_logger.Debug(NotificationsEventId.Default, null, $"SendSms- after MapSMSTaskToMessage");
IBridge _bridge = _engine.BridgeInstance(PreferenceKind.Sms, messages);
NotifyBase _sendSms = scope.Resolve<SmsNotifier>(new TypedParameter(typeof(IBridge), _bridge));
result = await _sendSms.Notify().ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"SendSms- after sms send: {result} -notifyid: {smsTask.NotificationId}");
private async Task<bool> SendEmail(string message)
_logger.Debug(NotificationsEventId.Default, null, $"SendEmail- message {message}");
//Deserialize the JSON email object and compose email and send to Send Grid
NotificationTask emailTask = (NotificationTask)JsonConvert.DeserializeObject(message, typeof(NotificationTask));
_logger.Debug(NotificationsEventId.Default, null, $"SendEmail- email deserialize: -notifyid: {emailTask.NotificationId}");
var messages = await MapEmailTaskToMessageAsync(emailTask).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"SendEmail- after MapEmailTaskToMessage");
IBridge _bridge = _engine.BridgeInstance(PreferenceKind.Email, messages);
NotifyBase _sendEmail = scope.Resolve<EmailNotifier>(new TypedParameter(typeof(IBridge), _bridge));
result = await _sendEmail.Notify().ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"SendEmail- after sms send: {result} -notifyid: {emailTask.NotificationId}");
private async Task<IList<Message>> MapEmailTaskToMessageAsync(NotificationTask emailTask)
var templateurls = await TemplateData.GetTemplateUrlsAsync(emailTask.Type, "email").ConfigureAwait(false);
IList<Message> messages = new List<Message>();
messages.Add(new Message()
Task = emailTask,
Type = emailTask.Type,
TemplateUrls = templateurls
});
return messages;
private IList<Message> MapSMSTaskToMessage(NotificationTask smsTask)
//TODO: Get template URLS if Applicable
Task = smsTask,
Type = smsTask.Type,
private async Task SetRedisVoiceOutage(NotificationTask voiceTask)
var redisVo = new RedisVoiceOutage();
var message = new PSE.Outage.Data.Message
Task = voiceTask,
Type = voiceTask.Type
};
redisVo.Message = message;
_logger.Debug(NotificationsEventId.Default, null, $"SetRedisVoiceOutage- before SetVoiceOutage -notifyid: {voiceTask.NotificationId}");
await Data.Common.SetVoiceOutage(redisVo, voiceTask.NotificationId).ConfigureAwait(false);
_logger.Debug(NotificationsEventId.Default, null, $"SetRedisVoiceOutage- after SetVoiceOutage -notifyid: {voiceTask.NotificationId}");
public string RunCountKey(TaskMessage task)
return $"runcount:{task.TaskId}";
public string StartTimeKey(TaskMessage task)
return $"start:{task.TaskId}";
//public void Init()
//{
// if (_context.HasQueueProcessorInitRun)
// return;
// else
// _context.HasQueueProcessorInitRun = true;
// _coreLogger.Trace(CoreEventId.TraceMethodEntry, null, "QueueProcessor init called");
// // log appsettings
// _context.LogSettings();
// //CreateEventSource
// _context.CreateEventSource("Outage Notifications");
// // cleanup objects
// Cleanup();
//}
//public void Cleanup()
// // use IStartup context to use clean up process if any
*/