有些用戶一直說系統發送的郵件一直收不到,投訴系統不正常,這時候怎么洗刷冤屈呢?將發送的每一封Email都保存到數據庫中,並記錄發送的日志,讓用戶無話可說。
自己創建3個表:
- MessageFailed - 失敗記錄(超過5次發送失敗就保存到這里)
- MessageQueue - 信息隊列 (成功了就放MessageSucceed,失敗5次就保存到MessageFailed)
- MessageSucceed - 成功記錄
使用FluentScheduler,直接在Web端調度,省去Windows服務程序。
FluentScheduler
Automated job scheduler with fluent interface.
相關代碼,我是用了IRegisteredObject,避免Application Pool和進程重啟造成的Job中斷等異常:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace DotNet.Business { using DotNet.Model; using DotNet.Business; using DotNet.Utilities; using FluentScheduler; using System.Web.Hosting; #region MessageRegistry public partial class MessageRegistry : Registry { public MessageRegistry() { //不允許重復進入 NonReentrantAsDefault(); // Schedule an IJob to run at an interval Schedule<MessageJob>().NonReentrant().ToRunNow().AndEvery(1).Seconds(); //// Schedule an IJob to run once, delayed by a specific time interval //Schedule<MessageJob>().ToRunOnceIn(5).Seconds(); //// Schedule a simple job to run at a specific time //Schedule(() => Console.WriteLine("It's 9:15 PM now.")).ToRunEvery(1).Days().At(21, 15); //// Schedule a more complex action to run immediately and on an monthly interval //Schedule<MessageJob>().ToRunNow().AndEvery(1).Months().OnTheFirst(DayOfWeek.Monday).At(3, 0); //// Schedule multiple jobs to be run in a single schedule //Schedule<MessageJob>().AndThen<MessageJob>().ToRunNow().AndEvery(5).Minutes(); } } #endregion #region MessageJob public partial class MessageJob : BaseManager, IBaseManager, IJob, IRegisteredObject { private readonly object _lock = new object(); private bool _shuttingDown; public MessageJob() { //Register this job with the hosting environment. //Allows for a more graceful stop of the job, in the case of IIS shutting down. HostingEnvironment.RegisterObject(this); } public void Execute() { lock (_lock) { if (_shuttingDown) return; //Do work, son! new MessageQueueManager(this.UserInfo).Resend(); } } public void Stop(bool immediate) { //Locking here will wait for the lock in Execute to be released until this code can continue. lock (_lock) { _shuttingDown = true; } HostingEnvironment.UnregisterObject(this); } } #endregion }
調度的時候,在Global.asax中調度如下:
//FluentScheduler任務調度 FluentScheduler.JobManager.Initialize(new DotNet.Business.MessageRegistry());
Message相關的代碼,MessageFailed中的郵件發送Error的記錄暫未實現:
#region 重新發送消息 /// <summary> /// 重新發送消息 /// </summary> /// <param name="id">主鍵</param> /// <returns>是否成功</returns> public bool Resend(MessageQueueEntity entity, int maxFailCount = 5) { bool result = false; if (entity.MessageType.ToLower().Contains("mail")) { if (MailUtil.Send(entity.Recipient, entity.Subject, entity.Body)) { //發送成功,移動數據到MessageSucceed表 MessageSucceedEntity entitySuccesed = new MessageSucceedEntity(); entitySuccesed.MessageType = entity.MessageType; entitySuccesed.Recipient = entity.Recipient; entitySuccesed.Subject = entity.Subject; entitySuccesed.Body = entity.Body; entitySuccesed.CreateOn = entity.CreateOn; new MessageSucceedManager(this.UserInfo).Add(entitySuccesed); //刪除MessageQueue表中的數據 //this.Delete(entity.Id); this.DeleteObject(entity.Id); result = true; } else { //更新MessageQueue表中的失敗次數 entity.FailCount = entity.FailCount + 1; this.UpdateObject(entity); if (entity.FailCount >= maxFailCount) { //發送失敗超過5次,移動數據到MessageFailed表 MessageFailedEntity entityFailed = new MessageFailedEntity(); entityFailed.MessageType = entity.MessageType; entityFailed.Recipient = entity.Recipient; entityFailed.Subject = entity.Subject; entityFailed.Body = entity.Body; entityFailed.FailCount = entity.FailCount; entityFailed.CreateOn = entity.CreateOn; //entityFailed.Error = ""; new MessageFailedManager(this.UserInfo).Add(entityFailed); //刪除MessageQueue表中的數據 //this.Delete(entity.Id); this.DeleteObject(entity.Id); result = false; } result = false; } } return result; } #endregion #region 重新發送所有隊列 /// <summary> /// 重新發送所有隊列 /// </summary> /// <returns>發送成功數量</returns> public int Resend(int maxFailCount = 5) { int result = 0; //每次發一封,避免超時,任務不停啟動而listEntity並未重新獲取 List<MessageQueueEntity> listEntity = this.GetList<MessageQueueEntity>(1, MessageQueueEntity.FieldId); foreach (var entity in listEntity) { if (this.Resend(entity, maxFailCount)) { result++; } } return result; } #endregion
因為這個后台Job的調度是郵件發送,其實MVC的項目也可以直接用上述代碼。