您的位置:首页 > 运维架构

应用框架设计若干问题探讨之----计划任务

2008-12-23 14:47 381 查看
在开发企业应用中免不了有一些需要系统自动触发和处理的计划性任务,如果应用框架能有一个简单易用的任务机制,对减轻开发和设计人员的工作难度有极大的帮助。本章将致力于描述一个简单易用的任务机制。

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 扩展话题

可能有很多需要继续扩展:
Ø 提供计划任务的管理类
Ø 提供计划任务数据库存储方案,并通过反射方式加载相应的执行体
Ø 提供计划任务编辑和维护的界面原型等等
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐