我的NopCommerce之旅(4): 定时任务之邮件
一、功能简介
用户购买物品生成订单后,系统将发送邮件提醒给用户
二、操作步骤
- 后台配置一个系统的默认发送邮箱
- 启动定时任务,这里包括多个任务,只需要启动邮件任务
- 查看邮件发送情况
三、数据库分析
- [dbo].[Log] 系统日志表,可查看邮件发送失败的异常信息
- [dbo].[EmailAccount] 系统发送邮件配置表
- [dbo].[QueuedEmail] 订单邮件序列表,[SentTries]为重试次数,默认尝试3次失败后不再发送。
- [dbo].[ScheduleTask] 定时任务信息表,存储定时任务信息。
四、源码解析
- 根据MVC命名规则,可定位到Nop.Admin.Controllers命名空间,
- 查看ScheduleTaskController的RunNow方法,可跟踪查看到任务调用机制。
- 通过反射类型,采用autofac实例化对象,然后执行。
- 任务实现Nop.Services.Tasks.ITask接口的Execute()方法,如Nop.Services.Messages.QueuedMessagesSendTask。
1 private ITask CreateTask(ILifetimeScope scope) 2 { 3 ITask task = null; 4 if (this.Enabled) 5 { 6 var type2 = System.Type.GetType(this.Type); 7 if (type2 != null) 8 { 9 object instance; 10 if (!EngineContext.Current.ContainerManager.TryResolve(type2, scope, out instance)) 11 { 12 //not resolved 13 instance = EngineContext.Current.ContainerManager.ResolveUnregistered(type2, scope); 14 } 15 task = instance as ITask; 16 } 17 } 18 return task; 19 }
1 /// <summary> 2 /// Executes the task 3 /// </summary> 4 /// <param name="throwException">A value indicating whether exception should be thrown if some error happens</param> 5 /// <param name="dispose">A value indicating whether all instances should be disposed after task run</param> 6 /// <param name="ensureRunOnOneWebFarmInstance">A value indicating whether we should ensure this task is run on one farm node at a time</param> 7 public void Execute(bool throwException = false, bool dispose = true, bool ensureRunOnOneWebFarmInstance = true) 8 { 9 ... 10 //initialize and execute 初始化成功后执行任务 11 var task = this.CreateTask(scope); 12 if (task != null) 13 { 14 this.LastStartUtc = DateTime.UtcNow; 15 if (scheduleTask != null) 16 { 17 //update appropriate datetime properties 18 scheduleTask.LastStartUtc = this.LastStartUtc; 19 scheduleTaskService.UpdateTask(scheduleTask); 20 } 21 task.Execute(); 22 this.LastEndUtc = this.LastSuccessUtc = DateTime.UtcNow; 23 } 24 } 25 catch (Exception exc) 26 { 27 this.Enabled = !this.StopOnError; 28 this.LastEndUtc = DateTime.UtcNow; 29 30 //log error 31 var logger = EngineContext.Current.ContainerManager.Resolve<ILogger>("", scope); 32 logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", this.Name, exc.Message), exc); 33 if (throwException) 34 throw; 35 } 36 37 if (scheduleTask != null) 38 { 39 //update appropriate datetime properties 40 scheduleTask.LastEndUtc = this.LastEndUtc; 41 scheduleTask.LastSuccessUtc = this.LastSuccessUtc; 42 scheduleTaskService.UpdateTask(scheduleTask); 43 } 44 45 //dispose all resources 46 if (dispose) 47 { 48 scope.Dispose(); 49 } 50 }
五、技术解析
- Autofac的依赖注入
- 反射