在吉日嘎拉DotNet.WebForm中使用FluentScheduler调度任务
有些用户一直说系统发送的邮件一直收不到,投诉系统不正常,这时候怎么洗刷冤屈呢?将发送的每一封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的项目也可以直接用上述代码。
专注、持续、微创新
站在巨人的肩膀上
方向不对,努力白费