NopCommerce之任务执行
2016-01-22 14:34
369 查看
NOP任务提供两种:手动执行(立即)和定时执行两种。
首先来说下手动任务执行过程,下图是NOP定时任务管理界面:
从上面可以看出,我们可以选择具体的任务来手动执行任务(立即执行),当点击【立即执行】按钮时会触发以下事件:
1、获取ScheduleTask对象(从数据库或缓存中)
2、创建Task对象,传入ScheduleTask对象作为构造参数,并为Task对象字段赋值
3、执行Task里的Execute()方法,该方法主要负责ITask实现类的创建,并执行Execute()方法,完成对任务的执行。
具体代码如下:
第8行:获取ScheduleTask对象(从数据库或缓存中)
第16行:、创建Task对象,传入ScheduleTask对象作为构造参数,并为Task对象字段赋值,然后我们进入到该方法体内看下
第15行:ITask实现类的创建,里面可能包括反射、关联对象的一些创建
第27行:执行实现了ITask类的Execute()方法,完成对任务的执行。最后更新字段。
二、第二种就是定时任务了,相对来说复杂点。
首先、在项目启动时的Application_Start()方法里,我们创建了任务管理类,
该类主要负责任务的初始化,添加到线程列表,任务的开始和停止,如下:
代码分析如下:
1、清空任务线程,
2、获取数据库内所有的任务
3、创建任务线程对象
4、创建Task对象
5、将Task对象存入 Dictionary<string, Task> 包装的集合中
6、最后将线程对象taskThread存入到 由List<TaskThread>包装集合中,该集合保存了所有任务的线程,
上面执行我们将所有需要执行的任务存入到List<TaskThread>包装集合中集合,我们下面就可以针对这些任务,执行定时任务,我们看下TaskManager类中Start()方法是如何写的:
上面的代码可以看出,NOP是循环线程集合中所有任务,并执行定时任务的。
上面的代码创建了Timer对象,在定时的时间内会执行TimerHandler()方法体中内容,方法体里的内容如下:
在方法体中会有个Run()方法,该方法会执行当前任务类中的Execute()方法,代码如下:
这样就实现了定时执行任务功能。。。
由于很少写博客,并且功力有限。只能这样了。。。欢迎指正
首先来说下手动任务执行过程,下图是NOP定时任务管理界面:
从上面可以看出,我们可以选择具体的任务来手动执行任务(立即执行),当点击【立即执行】按钮时会触发以下事件:
1、获取ScheduleTask对象(从数据库或缓存中)
2、创建Task对象,传入ScheduleTask对象作为构造参数,并为Task对象字段赋值
3、执行Task里的Execute()方法,该方法主要负责ITask实现类的创建,并执行Execute()方法,完成对任务的执行。
具体代码如下:
public ActionResult RunNow(int id) { if (!_permissionService.Authorize(StandardPermissionProvider.ManageScheduleTasks)) return AccessDeniedView(); try { var scheduleTask = _scheduleTaskService.GetTaskById(id); if (scheduleTask == null) throw new Exception("Schedule task cannot be loaded"); var task = new Task(scheduleTask); //ensure that the task is enabled task.Enabled = true; //do not dispose. otherwise, we can get exception that DbContext is disposed task.Execute(true, false); SuccessNotification(_localizationService.GetResource("Admin.System.ScheduleTasks.RunNow.Done")); } catch (Exception exc) { ErrorNotification(exc); } return RedirectToAction("List"); }
第8行:获取ScheduleTask对象(从数据库或缓存中)
第16行:、创建Task对象,传入ScheduleTask对象作为构造参数,并为Task对象字段赋值,然后我们进入到该方法体内看下
public void Execute(bool throwException = false, bool dispose = true) { this.IsRunning = true; //background tasks has an issue with Autofac //because scope is generated each time it's requested //that's why we get one single scope here //this way we can also dispose resources once a task is completed var scope = EngineContext.Current.ContainerManager.Scope(); var scheduleTaskService = EngineContext.Current.ContainerManager.Resolve<IScheduleTaskService>("", scope); var scheduleTask = scheduleTaskService.GetTaskByType(this.Type); try { var task = this.CreateTask(scope); if (task != null) { this.LastStartUtc = DateTime.UtcNow; if (scheduleTask != null) { //update appropriate datetime properties scheduleTask.LastStartUtc = this.LastStartUtc; scheduleTaskService.UpdateTask(scheduleTask); } //execute task task.Execute(); this.LastEndUtc = this.LastSuccessUtc = DateTime.UtcNow; } } catch (Exception exc) { this.Enabled = !this.StopOnError; this.LastEndUtc = DateTime.UtcNow; //log error var logger = EngineContext.Current.ContainerManager.Resolve<ILogger>("", scope); logger.Error(string.Format("Error while running the '{0}' schedule task. {1}", this.Name, exc.Message), exc); if (throwException) throw; } if (scheduleTask != null) { //update appropriate datetime properties scheduleTask.LastEndUtc = this.LastEndUtc; scheduleTask.LastSuccessUtc = this.LastSuccessUtc; scheduleTaskService.UpdateTask(scheduleTask); } //dispose all resources if (dispose) { scope.Dispose(); } this.IsRunning = false; }
第15行:ITask实现类的创建,里面可能包括反射、关联对象的一些创建
第27行:执行实现了ITask类的Execute()方法,完成对任务的执行。最后更新字段。
二、第二种就是定时任务了,相对来说复杂点。
首先、在项目启动时的Application_Start()方法里,我们创建了任务管理类,
protected void Application_Start() { //start scheduled tasks if (databaseInstalled) { TaskManager.Instance.Initialize(); TaskManager.Instance.Start(); } }
该类主要负责任务的初始化,添加到线程列表,任务的开始和停止,如下:
/// <summary> /// Initializes the task manager with the property values specified in the configuration file. /// </summary> public void Initialize() { this._taskThreads.Clear(); var taskService = EngineContext.Current.Resolve<IScheduleTaskService>(); var scheduleTasks = taskService .GetAllTasks() .OrderBy(x => x.Seconds) .ToList(); //group by threads with the same seconds foreach (var scheduleTaskGrouped in scheduleTasks.GroupBy(x => x.Seconds)) { //create a thread var taskThread = new TaskThread { Seconds = scheduleTaskGrouped.Key }; foreach (var scheduleTask in scheduleTaskGrouped) { var task = new Task(scheduleTask); taskThread.AddTask(task); } this._taskThreads.Add(taskThread); } //sometimes a task period could be set to several hours (or even days). //in this case a probability that it'll be run is quite small (an application could be restarted) //we should manually run the tasks which weren't run for a long time var notRunTasks = scheduleTasks //find tasks with "run period" more than 30 minutes .Where(x => x.Seconds >= _notRunTasksInterval) .Where(x => !x.LastStartUtc.HasValue || x.LastStartUtc.Value.AddSeconds(x.Seconds) < DateTime.UtcNow) .ToList(); //create a thread for the tasks which weren't run for a long time if (notRunTasks.Count > 0) { var taskThread = new TaskThread { RunOnlyOnce = true, Seconds = 60 * 5 //let's run such tasks in 5 minutes after application start }; foreach (var scheduleTask in notRunTasks) { var task = new Task(scheduleTask); taskThread.AddTask(task); } this._taskThreads.Add(taskThread); } }
代码分析如下:
1、清空任务线程,
2、获取数据库内所有的任务
3、创建任务线程对象
4、创建Task对象
5、将Task对象存入 Dictionary<string, Task> 包装的集合中
6、最后将线程对象taskThread存入到 由List<TaskThread>包装集合中,该集合保存了所有任务的线程,
上面执行我们将所有需要执行的任务存入到List<TaskThread>包装集合中集合,我们下面就可以针对这些任务,执行定时任务,我们看下TaskManager类中Start()方法是如何写的:
public void Start() { foreach (var taskThread in this._taskThreads) { taskThread.InitTimer(); } }
上面的代码可以看出,NOP是循环线程集合中所有任务,并执行定时任务的。
public void InitTimer() { if (this._timer == null) { this._timer = new Timer(new TimerCallback(this.TimerHandler), null, this.Interval, this.Interval); } }
上面的代码创建了Timer对象,在定时的时间内会执行TimerHandler()方法体中内容,方法体里的内容如下:
private void TimerHandler(object state) { this._timer.Change(-1, -1); this.Run(); if (this.RunOnlyOnce) { this.Dispose(); } else { this._timer.Change(this.Interval, this.Interval); } }
在方法体中会有个Run()方法,该方法会执行当前任务类中的Execute()方法,代码如下:
private void Run() { if (Seconds <= 0) return; this.StartedUtc = DateTime.UtcNow; this.IsRunning = true; foreach (Task task in this._tasks.Values) { task.Execute(); } this.IsRunning = false; }
这样就实现了定时执行任务功能。。。
由于很少写博客,并且功力有限。只能这样了。。。欢迎指正
相关文章推荐
- 快速理解Docker - 容器级虚拟化解决方案
- @property与@synthesize 的区别
- linux的命令date和hwclock
- shell编程-100例
- linux系统中GPIO的设置
- VGA timing (转)
- dokuwiki在nginx的配置
- linux win 的换行转换
- opentsdb采集的数据存放在哪里
- ffmpeg 转jpg文件为rgb32格式的文件
- shell批量转换iOS和Android图标
- opentsdb源码分析--region的名字
- linux下nproc的作用
- linux内核模块之间共享函数或者全局变量
- VS2013+OpenGL环境搭建好之后运行第一个程序出错
- Haproxy与OpenStack-API安全
- Hadoop中操作HDFS出现异常的解决方法
- 项目报错,tomcat中引起
- Apache+Tomcat集群配置
- 一些常用的查找方法,记录备用