예제 #1
0
        //public UniqueJob AddOrUpdate(string methodName, params object[] arguments)
        //{
        //    try
        //    {
        //        string signature = string.Format("{0}({1})", methodName, string.Join(",", arguments));

        //        if (this.repository.Any(p => p.Signature == signature))
        //            return null; // 已經存在,不要加入新的Job,回傳 NULL

        //        var job = new UniqueJob();
        //        job.Signature = signature;
        //        job.Status = EfJobQueueStatus.Enqueued;
        //        job.CreatedTime = DateTime.UtcNow;

        //        job = this.repository.Insert(job);
        //        return job;
        //    }
        //    catch (Exception ex)
        //    {
        //        this.logService.Error(ex);
        //        return null;
        //    }
        //}

        public void Remove(UniqueJob job)
        {
            try
            {
                this.repository.Delete(job);
            }
            catch (Exception ex)
            {
                this.logService.Error(ex);
            }
        }
예제 #2
0
        public void RetrySMS(int sendMessageHistoryId)
        {
            UniqueJob uniqueJob = null;

            try
            {
                uniqueJob = this.uniqueJobList.AddOrUpdate("RetrySMS", sendMessageHistoryId);
                if (uniqueJob == null)
                {
                    return;                    // Job 已經存在
                }
                using (var scope = this.unitOfWork.CreateTransactionScope())
                {
                    var sendMessageHistory = this.unitOfWork.Repository <SendMessageHistory>().GetById(sendMessageHistoryId);

                    decimal totalMessageCost = sendMessageHistory.MessageCost;

                    string currentProviderType = sendMessageHistory.ProviderName;

                    var providerTypesInOrder = GetSmsProviderTypes(currentProviderType);

                    // 由於使用預設的 Provider 無法發送成功,因此使用下一個 SmsProvider 發送
                    SmsProviderType userSmsProviderType = providerTypesInOrder[1];

                    ISmsProvider provider = GetProvider(userSmsProviderType, totalMessageCost); // 如果沒有找到,將會拋出例外

                    this.tradeService.RetrySMS(sendMessageHistory);

                    // 開始發送簡訊
                    provider.RetrySMS(sendMessageHistory.Id);

                    scope.Complete();
                }
            }
            catch (Exception ex)
            {
                this.logService.Error(ex);
                throw;
            }
            finally
            {
                if (uniqueJob != null)
                {
                    this.uniqueJobList.Remove(uniqueJob);
                }
            }
        }
예제 #3
0
        public void GetDeliveryReport(string requestId)
        {
            UniqueJob uniqueJob = null;

            try
            {
                uniqueJob = this.uniqueJobList.AddOrUpdate("GetDeliveryReport", requestId);
                if (uniqueJob == null)
                {
                    return;                    // Job 已經存在
                }
                using (var scope = this.unitOfWork.CreateTransactionScope())
                {
                    var deliveryReportQueueRepository = this.unitOfWork.Repository <DeliveryReportQueue>();

                    var deliveryReportQueue = deliveryReportQueueRepository.Get(p => p.RequestId == requestId);
                    if (deliveryReportQueue == null)
                    {
                        return;
                    }

                    ISmsProvider provider = GetProvider(deliveryReportQueue.ProviderName);

                    if (provider != null) // 取得DeliveryReport並沒有急迫性,等到簡訊供應商可供連線再取即可。
                    {
                        provider.GetDeliveryReport(requestId);
                    }

                    scope.Complete();
                }

                ////////////////////////////////////////
            }
            catch (Exception ex)
            {
                this.logService.Error("GetDeliveryReport({0})", requestId);
                this.logService.Error(ex);
                throw;
            }
            finally
            {
                if (uniqueJob != null)
                {
                    this.uniqueJobList.Remove(uniqueJob);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// 只有當 signature 不存在於 UniqueJobQueues
        /// 才會建立新的 UniqueJobQueue 物件,並回傳此物件
        /// 否則,將回傳 NULL
        /// </summary>
        public UniqueJob AddOrUpdate(string methodName, params object[] arguments)
        {
            try
            {
                string signature = string.Format("{0}({1})", methodName, string.Join(",", arguments));

                var job = this.repository.Get(p => p.Signature == signature);
                if (job != null)
                {
                    var expiryDate = DateTime.UtcNow.AddTicks(-1 * UniqueJobList.QueryInterval.Ticks);

                    if (job.CreatedTime >= expiryDate) // 超過指定時間,重設Job
                    {
                        return(null);                  // Job仍在執行中,不要加入新的Job,回傳 NULL
                    }
                    else
                    {
                        job.Signature   = signature;
                        job.Status      = EfJobQueueStatus.Enqueued;
                        job.CreatedTime = DateTime.UtcNow;

                        this.repository.Update(job);
                    }
                }
                else
                {
                    job = new UniqueJob();

                    job.Signature   = signature;
                    job.Status      = EfJobQueueStatus.Enqueued;
                    job.CreatedTime = DateTime.UtcNow;

                    job = this.repository.Insert(job);
                }

                return(job);
            }
            catch (Exception ex)
            {
                this.logService.Error(ex);
                return(null);
            }
        }
예제 #5
0
        public void HandleDeliveryReportTimeout()
        {
            UniqueJob uniqueJob = this.uniqueJobList.AddOrUpdate("HandleDeliveryReportTimeout");

            if (uniqueJob == null)
            {
                return;                    // Job 已經存在
            }
            try
            {
                using (var scope = this.unitOfWork.CreateTransactionScope())
                {
                    // 若一天之後,SendMessageHistory 狀態仍然為 MessageAccepted (仍未取得派送結果),
                    // 則將此筆 SendMessageHistory 狀態改成 DeliveryReportTimeout

                    var sendMessageRuleRepository    = this.unitOfWork.Repository <SendMessageRule>();
                    var sendMessageQueueRepository   = this.unitOfWork.Repository <SendMessageQueue>();
                    var sendMessageHistoryRepository = this.unitOfWork.Repository <SendMessageHistory>();

                    var expiryDate = DateTime.UtcNow.AddTicks(-1 * DeliveryReportQueue.QueryInterval.Ticks);

                    var entities = sendMessageHistoryRepository
                                   .GetMany(p =>
                                            (p.DeliveryStatus == DeliveryReportStatus.MessageAccepted || // Infobip
                                             p.DeliveryStatus == DeliveryReportStatus.Sending) &&        // Every8d
                                                                                                         // 已經過期
                                            p.CreatedTime < expiryDate)
                                   .ToList();

                    var sendMessageQueueIds = entities.Select(p => p.SendMessageQueueId).Distinct().ToList();
                    var sendMessageRuleIds  = entities.Select(p => p.SendMessageRuleId).Distinct().ToList();
                    var sendMessageQueues   = sendMessageQueueRepository.GetMany(p => sendMessageQueueIds.Contains(p.Id)).ToList();
                    var sendMessageRules    = sendMessageRuleRepository.GetMany(p => sendMessageRuleIds.Contains(p.Id)).ToList();

                    foreach (var entity in entities)
                    {
                        var oldDeliveryStatus = entity.DeliveryStatus;
                        var newDeliveryStatus = DeliveryReportStatus.DeliveryReportTimeout;
                        var sendMessageQueue  = sendMessageQueues.Find(p => p.Id == entity.SendMessageQueueId);
                        var sendMessageRule   = sendMessageRules.Find(p => p.Id == entity.SendMessageRuleId);

                        this.logService.Debug("{0}(簡訊編號:{1},序列編號:{2}),收訊門號{3}已超過{4}未經收到派送結果,接收狀態將由{5}改成{6}",
                                              AttributeHelper.GetColumnDescription(sendMessageRule.SendTimeType),
                                              sendMessageRule.Id,
                                              sendMessageQueue.Id,
                                              entity.DestinationAddress,
                                              DeliveryReportQueue.QueryInterval.ToString(),
                                              oldDeliveryStatus.ToString(),
                                              newDeliveryStatus.ToString());

                        entity.DeliveryStatus       = newDeliveryStatus;
                        entity.DeliveryStatusString = entity.DeliveryStatus.ToString();
                        entity.Delivered            = false;
                        sendMessageHistoryRepository.Update(entity);

                        // 如果發送失敗,就回補點數
                        // 20151123 Norman, Eric 要求發送失敗不回補點數
                        //tradeService.HandleSendMessageHistory(sendMessageRule, sendMessageQueue, entity);
                    }

                    foreach (var sendMessageQueueId in sendMessageQueueIds)
                    {
                        this.logService.Debug("簡訊序列編號:{0}),重新計算 SendMessageStatistic", sendMessageQueueId);

                        this.sendMessageStatisticService.AddOrUpdateSendMessageStatistic(sendMessageQueueId);
                    }

                    scope.Complete();
                }
            }
            catch (Exception ex)
            {
                this.logService.Error(ex);
                throw;
            }
            finally
            {
                this.uniqueJobList.Remove(uniqueJob);
            }
        }
예제 #6
0
        public void SendSMS(int sendMessageRuleId, DateTime sendTime)
        {
            UniqueJob uniqueJob = null;

            try
            {
                uniqueJob = this.uniqueJobList.AddOrUpdate("SendSMS", sendMessageRuleId, sendTime);
                if (uniqueJob == null)
                {
                    return;                    // Job 已經存在
                }
                // 如果在 SendMessageQueue 中已經有對應資料,就忽略
                if (this.unitOfWork.Repository <SendMessageQueue>().Any(p =>
                                                                        p.SendMessageRuleId == sendMessageRuleId &&
                                                                        p.SendTime == sendTime))
                {
                    return;
                }

                using (var scope = this.unitOfWork.CreateTransactionScope())
                {
                    SendMessageRule sendMessageRule = this.unitOfWork.Repository <SendMessageRule>().GetById(sendMessageRuleId);
                    if (sendMessageRule == null)
                    {
                        this.logService.Error("sendMessageRule is null (sendMessageRuleId: {0})", sendMessageRuleId);
                        return;
                    }

                    this.logService.Debug("CommonSmsService,發送簡訊(簡訊編號:{0},預定發送時間:{1},實際發送時間:{2})",
                                          sendMessageRule.Id,
                                          Converter.ToLocalTime(sendTime, sendMessageRule.ClientTimezoneOffset).ToString(Converter.Every8d_SentTime),
                                          Converter.ToLocalTime(DateTime.UtcNow, sendMessageRule.ClientTimezoneOffset).ToString(Converter.Every8d_SentTime));

                    ApplicationUser user = sendMessageRule.CreatedUser;

                    if (sendMessageRule.SendMessageRuleStatus != SendMessageRuleStatus.Ready)
                    {
                        return;
                    }

                    // 此簡訊規則下,所有收訊者資訊
                    var ruleReceivers = this.unitOfWork.Repository <MessageReceiver>().GetMany(p => p.SendMessageRuleId == sendMessageRule.Id).ToList();

                    // 目前有效的黑名單手機號碼 (E164)
                    var blackListMobiles = this.unitOfWork.Repository <Blacklist>()
                                           .GetMany(p => p.CreatedUser.Id == sendMessageRule.CreatedUser.Id && p.Enabled == true)
                                           .Select(p => p.Mobile)
                                           .Distinct()
                                           .ToList()
                                           .Select(p => MobileUtil.GetE164PhoneNumber(p))
                                           .ToList();

                    // 在黑名單的收訊者
                    var ruleReceiversInBlackList = ruleReceivers
                                                   .Where(p => blackListMobiles.Contains(MobileUtil.GetE164PhoneNumber(p.Mobile)))
                                                   .ToList();

                    // 不在黑名單的收訊者
                    var ruleReceiversNotInBlackList = ruleReceivers
                                                      .Where(p => !blackListMobiles.Contains(MobileUtil.GetE164PhoneNumber(p.Mobile)))
                                                      .ToList();

                    this.logService.Debug("CommonSmsService,發送簡訊(簡訊編號:{0},預定發送名單:{1})", sendMessageRuleId, ExcelBugFix.GetInformation(ruleReceivers.Select(p => p.Mobile).ToList()));
                    this.logService.Debug("CommonSmsService,發送簡訊(簡訊編號:{0},黑名單:{1})", sendMessageRuleId, ExcelBugFix.GetInformation(ruleReceiversInBlackList.Select(p => p.Mobile).ToList()));
                    this.logService.Debug("CommonSmsService,發送簡訊(簡訊編號:{0},實際發送名單:{1})", sendMessageRuleId, ExcelBugFix.GetInformation(ruleReceiversNotInBlackList.Select(p => p.Mobile).ToList()));

                    //List<string> detailInformations = new List<string>();
                    //detailInformations.AddRange(ExcelBugFix.GetDetailInformation(ruleReceivers.Select(p => p.Mobile).ToList())
                    //    .Select(p => string.Format("CommonSmsService,發送簡訊(簡訊編號:{0},預定發送名單(全):{1})", sendMessageRuleId, p))
                    //    .ToList());
                    //detailInformations.AddRange(ExcelBugFix.GetDetailInformation(ruleReceiversInBlackList.Select(p => p.Mobile).ToList())
                    //    .Select(p => string.Format("CommonSmsService,發送簡訊(簡訊編號:{0},黑名單(全):{1})", sendMessageRuleId, p))
                    //    .ToList());
                    //detailInformations.AddRange(ExcelBugFix.GetDetailInformation(ruleReceiversNotInBlackList.Select(p => p.Mobile).ToList())
                    //    .Select(p => string.Format("CommonSmsService,發送簡訊(簡訊編號:{0},實際發送名單(全):{1})", sendMessageRuleId, p))
                    //    .ToList());
                    //foreach (var detailInformation in detailInformations)
                    //{
                    //    this.logService.Debug(detailInformation);
                    //}

                    // 找出所有不同的發送內容
                    var sendBodies = ruleReceiversNotInBlackList.Select(p => p.SendBody).Distinct().ToList();

                    // 針對沒有執行預扣的簡訊規則,判斷是否有足夠點數進行簡訊發送作業

                    decimal totalMessageCost = ruleReceiversNotInBlackList.Sum(p => p.MessageCost);

                    if (!this.tradeService.ShouldWithhold(sendMessageRule.SendTimeType))
                    {
                        if (sendMessageRule.CreatedUser.SmsBalance < totalMessageCost)
                        {
                            string message = string.Format("執行{0}失敗(編號:{1}),使用者 {2} 點數不足,目前點數 {3} 點,發送所需點數 {4} 點",
                                                           AttributeHelper.GetColumnDescription(sendMessageRule.SendTimeType),
                                                           sendMessageRule.Id,
                                                           sendMessageRule.CreatedUser.UserName,
                                                           sendMessageRule.CreatedUser.SmsBalance,
                                                           totalMessageCost);

                            this.logService.Error(message);

                            throw new Exception(message);
                        }
                    }

                    // 找出可以使用的簡訊供應商(可連線且餘額足夠)

                    SmsProviderType userSmsProviderType = user.SmsProviderType;

                    ISmsProvider provider = GetProvider(userSmsProviderType, totalMessageCost); // 如果沒有找到,將會拋出例外

                    // 開始發送,將 SendMessageRule 狀態改變為 Sending (正在發送簡訊規則)
                    sendMessageRule.SendMessageRuleStatus = SendMessageRuleStatus.Sending;
                    sendMessageRule.CreatedUser           = user;
                    this.unitOfWork.Repository <SendMessageRule>().Update(sendMessageRule);

                    foreach (var sendBody in sendBodies)
                    {
                        // 依據傳送內容分群,每個群組使用一個SendMessageQueue,
                        // 此SendMessageQueue下,所有收訊者資訊
                        var queueReceivers = ruleReceiversNotInBlackList.Where(p => p.SendBody == sendBody).ToList();

                        var sendMessageQueue = new SendMessageQueue();
                        sendMessageQueue.SendMessageType    = sendMessageRule.SendMessageType;
                        sendMessageQueue.SendTime           = sendTime.ToUniversalTime(); // 預定發送訊息的時間(SendSMS經由Hangfire傳遞過來的sendTime,會將DateTimeKind轉為 Local,必須再轉成 Utc)
                        sendMessageQueue.SendTitle          = sendMessageRule.SendTitle;
                        sendMessageQueue.SendBody           = sendBody;
                        sendMessageQueue.SendCustType       = sendMessageRule.SendCustType;
                        sendMessageQueue.TotalReceiverCount = queueReceivers.Count();
                        sendMessageQueue.TotalMessageCost   = queueReceivers.Sum(p => p.MessageCost);
                        sendMessageQueue.SendMessageRuleId  = sendMessageRule.Id;

                        // 只針對非預先扣除的簡訊類型,對於打算要發送的內容進行扣點
                        this.tradeService.CreateSendMessageQueue(sendMessageRule, sendMessageQueue);

                        sendMessageQueue = this.unitOfWork.Repository <SendMessageQueue>().Insert(sendMessageQueue);

                        this.logService.Debug("CommonSmsService,發送簡訊(簡訊編號:{0},序列號碼:{1},發送名單:{2},發送內容:{3})",
                                              sendMessageRuleId,
                                              sendMessageQueue.Id,
                                              ExcelBugFix.GetInformation(queueReceivers.Select(p => p.Mobile).ToList()),
                                              sendBody);

                        provider.SendSMS(sendMessageQueue.Id); // TODO: 在 EVA 測試, 要先註解這一行,避免發送簡訊
                    } // foreach (var sendBody in sendBodies)

                    // 全部簡訊發送完畢,將 SendMessageRule 狀態改變為 Sending (簡訊規則已發送完畢)
                    sendMessageRule.SendMessageRuleStatus = SendMessageRuleStatus.Sent;
                    this.unitOfWork.Repository <SendMessageRule>().Update(sendMessageRule);

                    // http://www.dotblogs.com.tw/rainmaker/archive/2015/08/19/153169.aspx

                    // 檢查此簡訊規則是否任務完成,
                    //  如果是的話,將狀態設為 Finish
                    //  如果否的話,將狀態設為 Ready (等待下次週期簡訊發送)

                    bool isFinish = !sendMessageRule.GetNextSendTime().HasValue;
                    sendMessageRule.SendMessageRuleStatus = isFinish ? SendMessageRuleStatus.Finish : SendMessageRuleStatus.Ready;
                    this.unitOfWork.Repository <SendMessageRule>().Update(sendMessageRule);

                    // 針對預先扣點的發送時間類型,進行黑名單的收訊者 - 退還點數
                    this.tradeService.HandleReceiversInBlackList(sendMessageRule, ruleReceiversInBlackList);

                    scope.Complete();
                }

                ////////////////////////////////////////
            }
            catch (Exception ex)
            {
                this.logService.Error(ex);
                throw;
            }
            finally
            {
                if (uniqueJob != null)
                {
                    this.uniqueJobList.Remove(uniqueJob);
                }
            }
        }