应用框架设计若干问题探讨之----计划任务
2008-12-23 14:47
381 查看
在开发企业应用中免不了有一些需要系统自动触发和处理的计划性任务,如果应用框架能有一个简单易用的任务机制,对减轻开发和设计人员的工作难度有极大的帮助。本章将致力于描述一个简单易用的任务机制。
{
/// <summary>
/// 计算下一次触发时间。
/// </summary>
/// <remarks>
/// 返回值为DateTime.MinValue时,策略关联的任务完成并从计划的执行队列删除。
/
4000
// </remarks>
/// <param name="triggerCount">策略被触发过的次数。</param>
/// <param name="lastTime">触发相对时间。</param>
/// <returns>返回下一次触发的时间。</returns>
DateTime CalcNextTime(int triggerCount , DateTime lastTime);
}
首先设计触发策略接口,给程序员自定义的机制,框架本身也实现了两个触发策略,一个基于定时器模式,一个基于日历模式。
更多模式需要自己定义。
/// 计划任务。
/// </summary>
public sealed class Task :IDisposable
{
#region Fields
private TaskCallback _callback;
private Object _stateObj;
private ITriggerPolicy _policy;
private int _maxCount;
private IMutex _lock;
private Timer _timer;
private TaskState _state;
private int _triggerCount;
private int _currentPolicyTriggerCount;
private DateTime _lastTriggerTime;
private Exception _lastException;
private Hashtable _properties = Hashtable.Synchronized(new Hashtable());
#endregion
#region Constructor(s)
/// <summary>
/// 用指定的策略初始化类 <see cref="Task"/> 的新实例。
/// </summary>
/// <param name="callback">任务回调委托。</param>
/// <param name="policy">任务触发策略。</param>
public Task(TaskCallback callback, ITriggerPolicy policy)
:this(callback, null, policy)
{
}
/// <summary>
/// 用指定的策略和回调状态对象初始化类 <see cref="Task"/> 的新实例。
/// </summary>
/// <param name="callback">任务回调委托。</param>
/// <param name="stateObj">回调状态对象。</param>
/// <param name="policy">任务触发策略。</param>
public Task(TaskCallback callback, Object stateObj, ITriggerPolicy policy)
:this(callback, stateObj, policy, Int32.MaxValue)
{
}
/// <summary>
/// 用指定的策略、回调状态对象和最大执行次数初始化类 <see cref="Task"/> 的新实例。
/// </summary>
/// <param name="callback">任务回调委托。</param>
/// <param name="stateObj">回调状态对象。</param>
/// <param name="policy">任务触发策略。</param>
/// <param name="maxCount">最大执行次数。</param>
public Task(TaskCallback callback, Object stateObj, ITriggerPolicy policy, int maxCount)
{
Exceptions.ThrowIfNull(callback, "callback");
Exceptions.ThrowIfNull(policy, "policy");
Exceptions.ThrowIfNotPositive(maxCount, "maxCount");
this._callback = callback;
this._stateObj = stateObj;
this._policy = policy;
this._maxCount = maxCount;
this._lock = new ThreadMutex();
this._state = TaskState.Ready;
this._triggerCount = 0;
this._currentPolicyTriggerCount = 0;
this._lastTriggerTime = DateTime.MinValue;
this._lastException = null;
this._timer = new Timer(new TimerCallback(Task.TimerProxy), this, -1, -1);
}
#endregion
#region Properties
/// <summary>
/// 获取任务状态。
/// </summary>
public TaskState State
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _state;
}
}
}
/// <summary>
/// 获取任务被触发的次数。
/// </summary>
public int TriggerCount
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _triggerCount;
}
}
}
/// <summary>
/// 获取当前策略被触发的次数。
/// </summary>
public int CurrentPolicyTriggerCount
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _currentPolicyTriggerCount;
}
}
}
/// <summary>
/// 获取最后触发时间。
/// 没有触发的任务为DateTime.MinValue。
/// </summary>
public DateTime LastTriggerTime
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _lastTriggerTime;
}
}
}
/// <summary>
/// 获取最后一次触发的异常。
/// </summary>
public Exception LastException
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _lastException;
}
}
}
/// <summary>
/// 获取、设置任务的命名属性。
/// </summary>
/// <param name="name">属性名称。</param>
/// <returns>属性值。</returns>
public Object this[string name]
{
get
{
Exceptions.ThrowIfEmpty(name, "name");
return this._properties[name];
}
set
{
Exceptions.ThrowIfEmpty(name, "name");
this._properties[name] = value;
}
}
#endregion
#region Methods
/// <summary>
/// 启动任务。
/// </summary>
public void Startup()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
// 任务已经被启动
if (this._state != TaskState.Ready)
return;
this._state = TaskState.Scheduling;
ChangeTimer();
// 触发策略没有有效的触发时间,任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
}
}
/// <summary>
/// 停止任务。
/// </summary>
public void Shutdown()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
return;
// 任务已经停止
if (this._state == TaskState.Ready)
return;
// 停止定时器
this._timer.Change(-1, -1);
this._state = TaskState.Ready;
}
}
/// <summary>
/// 修改任务触发策略。
/// </summary>
/// <param name="policy">触发策略。</param>
public void Change(ITriggerPolicy policy)
{
Exceptions.ThrowIfNull(policy, "policy");
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
// 停止定时器
this._timer.Change(-1, -1);
this._policy = policy;
this._currentPolicyTriggerCount = 0;
// 如果当前状态不是就绪 , 修改定时器
if (this._state != TaskState.Ready)
{
ChangeTimer();
// 触发策略没有有效的触发时间,任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
}
}
}
/// <summary>
/// 任务对象传递给 <see cref="System.Threading.Timer"/> 的定时器回调委托。
/// </summary>
/// <param name="state">状态对象,它是 <see cref="Task"/>类的实例。</param>
private static void TimerProxy(Object state)
{
Task task = (Task)state;
Exception currException = null;
// 执行前检测
if (task.PreExecute())
{
try
{
task._callback(task, task._stateObj);
}
catch (Exception e)
{
currException = e;
}
// 执行后处理
task.PostExecute(currException);
}
}
// 执行前检测
private bool PreExecute()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置,不在执行
if (this._state == TaskState.Disposed)
return false;
// 修改状态以及相关执行计数
this._state = TaskState.Executing;
this._triggerCount++;
this._currentPolicyTriggerCount++;
this._lastTriggerTime = DateTime.Now;
}
return true;
}
// 执行后处理
private void PostExecute(Exception e)
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
return ;
// 如果执行次数达到最大可执行次数,处置该任务
if (this._maxCount == this._triggerCount)
{
this.Dispose();
return;
}
// 记录最后异常
if( e != null)
this._lastException = e;
ChangeTimer();
// 触发策略没有有效的触发时间,任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
this._state = TaskState.Scheduling;
}
}
private void ChangeTimer()
{
DateTime now = DateTime.Now;
DateTime nextTime = this._policy.CalcNextTime(this._currentPolicyTriggerCount, now);
if (nextTime < now)
{
this.Dispose();
return;
}
int interval = (int)((nextTime - now).TotalMilliseconds);
this._timer.Change(interval , -1);
}
#endregion
#region IDisposable 成员
/// <summary>
/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
/// </summary>
public void Dispose()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
if (this._state == TaskState.Disposed)
return;
this._timer.Change(-1, -1);
this._timer.Dispose();
this._state = TaskState.Disposed;
}
GC.SuppressFinalize(this);
}
#endregion
}
}
Task类通过使用者提供的任务执行体和触发策略来调度任务。它封装了Timer类并提供了更多的业务元素:
Ø 提供了自定义触发策略机制
Ø 提供了一些应用级的属性
Ø 提供了一些应用自定义属性
{
static void Main(string[] args)
{
// 定义一个最初间隔10秒,后续间隔5秒执行的任务;并要求最多执行10次
Task task = new Task(TaskProc,null,
new TimerTriggerPolicy(new TimeInterval(10),new TimeInterval(5)), 10);
task["name"] = "First Task";
task.Startup();
Console.ReadLine();
task.Dispose();
}
private static void TaskProc(Task task, Object state)
{
Console.WriteLine("任务:{0}", task["name"]);
Console.WriteLine("/t执行次数 {0} , 执行时间 {1}", task.TriggerCount,DateTime.Now);
// 当执行5次后,修改触发策略
if (task.TriggerCount == 5)
task.Change(new CalendarTriggerPolicy("0,15,30,45;*;*;*;*;1-5"));
}
}
使用任务类就像Timer类一样简单。
Ø 提供计划任务的管理类
Ø 提供计划任务数据库存储方案,并通过反射方式加载相应的执行体
Ø 提供计划任务编辑和维护的界面原型等等
1.1 需求分析
所谓计划任务,就是指在某个时点执行相应的处理。我们在.NET中自然的想到了System.Threading.Timer,它已经提供了一种定时器方式的执行某种任务的机制。但在企业应用中,它显得过于简单,我们需要它提供相应的扩展能力,特别是能定制触发策略。1.2 详细设计
从设计角度,扩展Timer类是一个不错的想法;提供更加灵活的触发策略触发,给出一个简单易用的任务类。1.2.1 ITriggerPolicy接口
public interface ITriggerPolicy{
/// <summary>
/// 计算下一次触发时间。
/// </summary>
/// <remarks>
/// 返回值为DateTime.MinValue时,策略关联的任务完成并从计划的执行队列删除。
/
4000
// </remarks>
/// <param name="triggerCount">策略被触发过的次数。</param>
/// <param name="lastTime">触发相对时间。</param>
/// <returns>返回下一次触发的时间。</returns>
DateTime CalcNextTime(int triggerCount , DateTime lastTime);
}
首先设计触发策略接口,给程序员自定义的机制,框架本身也实现了两个触发策略,一个基于定时器模式,一个基于日历模式。
更多模式需要自己定义。
1.2.2 Task类
/// <summary>/// 计划任务。
/// </summary>
public sealed class Task :IDisposable
{
#region Fields
private TaskCallback _callback;
private Object _stateObj;
private ITriggerPolicy _policy;
private int _maxCount;
private IMutex _lock;
private Timer _timer;
private TaskState _state;
private int _triggerCount;
private int _currentPolicyTriggerCount;
private DateTime _lastTriggerTime;
private Exception _lastException;
private Hashtable _properties = Hashtable.Synchronized(new Hashtable());
#endregion
#region Constructor(s)
/// <summary>
/// 用指定的策略初始化类 <see cref="Task"/> 的新实例。
/// </summary>
/// <param name="callback">任务回调委托。</param>
/// <param name="policy">任务触发策略。</param>
public Task(TaskCallback callback, ITriggerPolicy policy)
:this(callback, null, policy)
{
}
/// <summary>
/// 用指定的策略和回调状态对象初始化类 <see cref="Task"/> 的新实例。
/// </summary>
/// <param name="callback">任务回调委托。</param>
/// <param name="stateObj">回调状态对象。</param>
/// <param name="policy">任务触发策略。</param>
public Task(TaskCallback callback, Object stateObj, ITriggerPolicy policy)
:this(callback, stateObj, policy, Int32.MaxValue)
{
}
/// <summary>
/// 用指定的策略、回调状态对象和最大执行次数初始化类 <see cref="Task"/> 的新实例。
/// </summary>
/// <param name="callback">任务回调委托。</param>
/// <param name="stateObj">回调状态对象。</param>
/// <param name="policy">任务触发策略。</param>
/// <param name="maxCount">最大执行次数。</param>
public Task(TaskCallback callback, Object stateObj, ITriggerPolicy policy, int maxCount)
{
Exceptions.ThrowIfNull(callback, "callback");
Exceptions.ThrowIfNull(policy, "policy");
Exceptions.ThrowIfNotPositive(maxCount, "maxCount");
this._callback = callback;
this._stateObj = stateObj;
this._policy = policy;
this._maxCount = maxCount;
this._lock = new ThreadMutex();
this._state = TaskState.Ready;
this._triggerCount = 0;
this._currentPolicyTriggerCount = 0;
this._lastTriggerTime = DateTime.MinValue;
this._lastException = null;
this._timer = new Timer(new TimerCallback(Task.TimerProxy), this, -1, -1);
}
#endregion
#region Properties
/// <summary>
/// 获取任务状态。
/// </summary>
public TaskState State
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _state;
}
}
}
/// <summary>
/// 获取任务被触发的次数。
/// </summary>
public int TriggerCount
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _triggerCount;
}
}
}
/// <summary>
/// 获取当前策略被触发的次数。
/// </summary>
public int CurrentPolicyTriggerCount
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _currentPolicyTriggerCount;
}
}
}
/// <summary>
/// 获取最后触发时间。
/// 没有触发的任务为DateTime.MinValue。
/// </summary>
public DateTime LastTriggerTime
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _lastTriggerTime;
}
}
}
/// <summary>
/// 获取最后一次触发的异常。
/// </summary>
public Exception LastException
{
get
{
using (AutoReaderLock rlock = new AutoReaderLock(this._lock))
{
return _lastException;
}
}
}
/// <summary>
/// 获取、设置任务的命名属性。
/// </summary>
/// <param name="name">属性名称。</param>
/// <returns>属性值。</returns>
public Object this[string name]
{
get
{
Exceptions.ThrowIfEmpty(name, "name");
return this._properties[name];
}
set
{
Exceptions.ThrowIfEmpty(name, "name");
this._properties[name] = value;
}
}
#endregion
#region Methods
/// <summary>
/// 启动任务。
/// </summary>
public void Startup()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
// 任务已经被启动
if (this._state != TaskState.Ready)
return;
this._state = TaskState.Scheduling;
ChangeTimer();
// 触发策略没有有效的触发时间,任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
}
}
/// <summary>
/// 停止任务。
/// </summary>
public void Shutdown()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
return;
// 任务已经停止
if (this._state == TaskState.Ready)
return;
// 停止定时器
this._timer.Change(-1, -1);
this._state = TaskState.Ready;
}
}
/// <summary>
/// 修改任务触发策略。
/// </summary>
/// <param name="policy">触发策略。</param>
public void Change(ITriggerPolicy policy)
{
Exceptions.ThrowIfNull(policy, "policy");
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
// 停止定时器
this._timer.Change(-1, -1);
this._policy = policy;
this._currentPolicyTriggerCount = 0;
// 如果当前状态不是就绪 , 修改定时器
if (this._state != TaskState.Ready)
{
ChangeTimer();
// 触发策略没有有效的触发时间,任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
}
}
}
/// <summary>
/// 任务对象传递给 <see cref="System.Threading.Timer"/> 的定时器回调委托。
/// </summary>
/// <param name="state">状态对象,它是 <see cref="Task"/>类的实例。</param>
private static void TimerProxy(Object state)
{
Task task = (Task)state;
Exception currException = null;
// 执行前检测
if (task.PreExecute())
{
try
{
task._callback(task, task._stateObj);
}
catch (Exception e)
{
currException = e;
}
// 执行后处理
task.PostExecute(currException);
}
}
// 执行前检测
private bool PreExecute()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置,不在执行
if (this._state == TaskState.Disposed)
return false;
// 修改状态以及相关执行计数
this._state = TaskState.Executing;
this._triggerCount++;
this._currentPolicyTriggerCount++;
this._lastTriggerTime = DateTime.Now;
}
return true;
}
// 执行后处理
private void PostExecute(Exception e)
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
// 任务已经被处置
if (this._state == TaskState.Disposed)
return ;
// 如果执行次数达到最大可执行次数,处置该任务
if (this._maxCount == this._triggerCount)
{
this.Dispose();
return;
}
// 记录最后异常
if( e != null)
this._lastException = e;
ChangeTimer();
// 触发策略没有有效的触发时间,任务已经被处置
if (this._state == TaskState.Disposed)
throw new ObjectDisposedException(SR.ObjectDisposed_Task);
this._state = TaskState.Scheduling;
}
}
private void ChangeTimer()
{
DateTime now = DateTime.Now;
DateTime nextTime = this._policy.CalcNextTime(this._currentPolicyTriggerCount, now);
if (nextTime < now)
{
this.Dispose();
return;
}
int interval = (int)((nextTime - now).TotalMilliseconds);
this._timer.Change(interval , -1);
}
#endregion
#region IDisposable 成员
/// <summary>
/// 执行与释放或重置非托管资源相关的应用程序定义的任务。
/// </summary>
public void Dispose()
{
using (AutoWriterLock wlock = new AutoWriterLock(this._lock))
{
if (this._state == TaskState.Disposed)
return;
this._timer.Change(-1, -1);
this._timer.Dispose();
this._state = TaskState.Disposed;
}
GC.SuppressFinalize(this);
}
#endregion
}
}
Task类通过使用者提供的任务执行体和触发策略来调度任务。它封装了Timer类并提供了更多的业务元素:
Ø 提供了自定义触发策略机制
Ø 提供了一些应用级的属性
Ø 提供了一些应用自定义属性
1.3 应用实例
class Program{
static void Main(string[] args)
{
// 定义一个最初间隔10秒,后续间隔5秒执行的任务;并要求最多执行10次
Task task = new Task(TaskProc,null,
new TimerTriggerPolicy(new TimeInterval(10),new TimeInterval(5)), 10);
task["name"] = "First Task";
task.Startup();
Console.ReadLine();
task.Dispose();
}
private static void TaskProc(Task task, Object state)
{
Console.WriteLine("任务:{0}", task["name"]);
Console.WriteLine("/t执行次数 {0} , 执行时间 {1}", task.TriggerCount,DateTime.Now);
// 当执行5次后,修改触发策略
if (task.TriggerCount == 5)
task.Change(new CalendarTriggerPolicy("0,15,30,45;*;*;*;*;1-5"));
}
}
使用任务类就像Timer类一样简单。
1.4 扩展话题
可能有很多需要继续扩展:Ø 提供计划任务的管理类
Ø 提供计划任务数据库存储方案,并通过反射方式加载相应的执行体
Ø 提供计划任务编辑和维护的界面原型等等
相关文章推荐
- Yii框架设计计划任务脚本+linux下crontab执行
- 应用框架的设计与实现——.NET平台4.2代码测试问题解决
- 写书计划启动!《.NET通信框架的设计、实现与应用》
- 企业级系统架构设计技术与互联网应用技术结合主题一 大规模并发性能问题探讨
- 4程序员小飞原计划三天完成某个任务,现在是第三天的下午,他马上就可以做完。但是在实现功能的过程中,他越来越意识到自己原来设计中的弱点,他应该采取另一个办法,才能避免后面集成阶段的额外工作。但是他如果现在就改弦更张,那势必要影响自己原来估计的准确性,并且会花费额外的时间,这样他的老板、同事也许会因此看不起他。如果他按部就班地按既定设计完成,还要花更多时间在后续集成上,但那就不是他个人的问题了,怎么办
- 企业级应用框架设计备忘录
- 关于中小规模生产销售型应用技术框架的想法和问题,请大家多多提点
- 浅谈电路设计中应用DDR3处理缓存问题
- 应用框架的设计与实现——.NET平台(4.2 Remoting 客户端激活)
- 设计模式的实际应用——在C#中解决单客户端窗口数据并发问题(2010-08-04)
- 应用框架的设计与实现——.NET平台(6 自定配置文件节读取类)
- Word2013中公式应用的若干问题
- Windows 8 商店应用开发设计十大常见问题(一)
- WinForm企业应用框架设计【一】界限划分与动态创建WCF服务(no svc!no serviceActivations!)
- 蓝牙(BLE)应用框架接口设计和应用开发——以TI CC2541为例
- Maemo Linux手机平台系列分析:(14) Maemo平台开发之 设计D-Bus server时要注意的若干问题
- 仿照Windows任务计划的数据库设计
- AngularJS实际项目应用——单元测试框架设计
- 车载系统之 Windows CE 应用软件框架设计
- 一步一步教你创建SQL 2005计划任务应用图解教程