NOP任务提供两种:手动执行(立即)和定时执行两种。

首先来说下手动任务执行过程,下图是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 > )
{
var taskThread = new TaskThread
{
RunOnlyOnce = true,
Seconds = * //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(-, -);
this.Run();
if (this.RunOnlyOnce)
{
this.Dispose();
}
else
{
this._timer.Change(this.Interval, this.Interval);
}
}

在方法体中会有个Run()方法,该方法会执行当前任务类中的Execute()方法,代码如下:

    private void Run()
{
if (Seconds <= )
return; this.StartedUtc = DateTime.UtcNow;
this.IsRunning = true;
foreach (Task task in this._tasks.Values)
{
task.Execute();
}
this.IsRunning = false;
}

这样就实现了定时执行任务功能。。。

由于很少写博客,并且功力有限。只能这样了。。。欢迎指正

												

NopCommerce之任务执行的更多相关文章

  1. Bash 翻译

    Bash参考手册 目录 1简介 1.1什么是Bash? 1.2什么是shell? 2定义 3基本外壳功能 3.1 Shell语法 3.1.1外壳操作 3.1.2报价 3.1.2.1逃逸角色 3.1.2 ...

  2. NopCommerce 执行计划任务不同Services协调操作导致更新数据失败的问题!

    问题描述: 在Nop的计划任务里需要两个任务协调操作 _shipmentService.InsertShipment(shipment); _orderProcessingService.Ship(s ...

  3. NopCommerce 框架系列(二)

    这一篇,让我们一起来认识一下 NopCommerce 的整体目录结构

  4. Portal.MVC —— nopcommerce的简化版

    Portal.MVC 简介 项目是基于MVC4+EF,带有角色,权限,用户中心及账户相关(登录,注册,修改密码,找回密码等)等基本功能.参考的开源项目 nopcommerce,这是一个电商架构的MVC ...

  5. [转]NopCommerce之旅: 应用启动

    本文转自:http://www.cnblogs.com/devilsky/p/5359881.html 我的NopCommerce之旅(6): 应用启动   一.基础介绍 Global.asax 文件 ...

  6. 参照nopCommerce框架开发(NextCMS)

    很久没有更新博客了,现在已经不写.NET,转前端半年多了. 半年前在创业公司,做电子商务网站,用的是NopCommerce框架(3.2),这个框架还是相当不错的,经过一段时间的摸索,基本入门,于是就开 ...

  7. NopCommerce 3.80框架研究(一) 数据访问与持久化

    NopCommerce 是一个国外的开源电商系统.3.80版本使用EF6.0 和.Net Framework 4.5.1 并引入了Autofac , Autofac是一款IOC框架,比较于其他的IOC ...

  8. nopCommerce 数据库初试化及数据操作

    系统启动时执行任务:IStartupTask,启动时执行的任务主要是数据库的初始化和加载. IStartupTask调用IEfDataProvider进行数据库的初始化. IEfDataProvide ...

  9. nopCommerce 数据缓存

    为了提高一个系统或网站的性能和IO吞吐量,我们一般都会采用缓存技术.当然NopCommerce也不例外,本文我们就来给大家分析一下nop中Cache缓存相关类设计.核心源码及实现原理. 一.Nop.C ...

随机推荐

  1. 分享20个吸引眼球的高品质免费PSD网站模板

    当你设计网站的时候,你需要一个美丽的界面来吸引你的听众.在这篇文章中,我将分享一些吸引眼球的商业PSD模板,你可以从中受到启发 EaglesTroop Business Bonfire Pocket ...

  2. 从一个例子中体会React的基本面

    [起初的准备工作] npm init npm install --save react react-dom npm install --save-dev html-webpack-plugin web ...

  3. 奇怪吸引子---Rucklidge

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  4. python排序算法的实现-插入

    1.算法: 设有一组关键字{ K 1 , K 2 ,…, K n }:排序开始就认为 K 1 是一个有序序列:让 K 2 插入上述表长为 1 的有序序列,使之成为一个表长为 2 的有序序列:然后让 K ...

  5. asp.net 多个文件同时下载

    1.首先读取文件夹下的文件,可能同时存在多个文件 2.选中文件,然后点击下载,同时可以选择多个文件. 思路:通过生产压缩包的形式进行下载,然后再清楚压缩包,这样用户可以一次性全部下载下来. 一.获取目 ...

  6. [转载] Redis

    转载:http://snowolf.iteye.com/blog/1630697 大约一年多前,公司同事开始使用Redis,不清楚是配置,还是版本的问题,当时的Redis经常在使用一段时间后,连接爆满 ...

  7. iis7下iis安全狗不能用怎么办(安装iis6兼容性)

    is7下iis安全狗不能用怎么办 | 浏览:126 | 更新:2015-05-14 17:11 1 2 3 4 5 6 分步阅读 windows系统iis安全狗是常用的一款软件,针对网站使用很方便.在 ...

  8. Kafka - 消费接口分析

    1.概述 在 Kafka 中,官方对外提供了两种消费 API,一种是高等级消费 API,另一种是低等级的消费 API.在 <高级消费 API>一文中,介绍了其高级消费的 API 实现.今天 ...

  9. AX2012 R3升级CU8的一些错误

    AX2012 R3安装升级包CU8后进入系统,系统会提示打开软件升级清单“Software update checklist”,清单列出了升级要做的一系列动作. 在进行到编译应用时“Compile a ...

  10. makeimg

    >./simg2img [system.img] [system2.img]>mount -o loop [system2.img] [s/]>./make_ext4fs -s -l ...