文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>ScheduledJob的实现

ScheduledJob的实现

时间:2011-02-20  来源:修身养性写博客

Demo实现
    下面通过一个简单的Demo说明上述实现:Scheduled Job实现每天定时Mail提醒

1.新建配置档JobSetting,用于配置每个Job要执行的方法和执行时间和频率等信息

<?xml version="1.0" encoding="utf-8" ?>
<Jobs>
<Job Id="140" Name="DailyRoutineJob">
<Dll>
<FileName>ScheduleJob.dll</FileName>
<TypeName>ScheduleJob.DailyInfo</TypeName>
<ConstructArgs />
<MethodName>SendDailyInfo</MethodName>
<Args></Args>
</Dll>
<ExecutionTime Type="Monthly">
<Day>All</Day>
<Time>08:00</Time>
</ExecutionTime>
<EmailAddress>[email protected]</EmailAddress>
</Job>
<Job Id="141" Name="WeeklyRoutineJob">
<Dll>
<FileName>ScheduleJob.dll</FileName>
<TypeName>ScheduleJob.WeeklyInfo</TypeName>
<ConstructArgs />
<MethodName>SendWeeklyInfo</MethodName>
<Args></Args>
</Dll>
<ExecutionTime Type="Monthly">
<Day>1</Day>
<Time>08:00</Time>
</ExecutionTime>
<EmailAddress> [email protected]</EmailAddress>
</Job>
</Jobs>

2.新增一个类库专案:ScheduledJob,注意命名空间和类名,方法名需要和上面的配置档保持一致。

namespace ScheduleJob
{
public class DailyInfo
{
public void SendDailyInfo(string msg)
{
//在此分析发送msg给特定的人员
        }
}
}

 

3.建立专案Windows Service:myScheduledJob
   在OnStart方法中,启动监控并加载DLL组件至缓存

     protected override void OnStart(string[] args)
{
systemPath = ConfigurationManager.AppSettings["SystemPath"].ToString();
dllForderName = ConfigurationManager.AppSettings["DllForderName"].ToString();
jobSettingName = ConfigurationManager.AppSettings["JobSettingName"].ToString();
logForderPath = ConfigurationManager.AppSettings["LogForderName"].ToString();
writeLog("Assembly Watcher Started  at " + DateTime.Now.ToString());
watcherChangedTimes = new Dictionary<string, DateTime>();
assemblyPool = new Dictionary<string, Assembly>();
timerPool = new Dictionary<string, Timer>();
//监控特定文件夹,监控DLL组件的异动
dllWatcher = new FileSystemWatcher();
dllWatcher.Path = systemPath + @"\" + dllForderName;
dllWatcher.IncludeSubdirectories = false;
dllWatcher.Filter = "*.dll";
dllWatcher.NotifyFilter = NotifyFilters.LastWrite;
dllWatcher.EnableRaisingEvents = true;
dllWatcher.Changed += new FileSystemEventHandler(dllWatcher_Changed);
writeLog("Begin Set TimerPool...");
//加载DLL组件并缓存
setTimerPool();
writeLog("Set TimerPool Completed");
}
void dllWatcher_Changed(object sender, FileSystemEventArgs e)
{
//60秒内同一个文件只处理一次,此时间间隔可根据具体情况修改:用于解决同一文件更新的多次事件触发问题
#region
DateTime now = DateTime.Now;
int reloadSeconds = 60;
if (watcherChangedTimes.ContainsKey(e.FullPath))
{
if (now.Subtract(watcherChangedTimes[e.FullPath]).TotalSeconds < reloadSeconds)
{
return;
}
else
{
watcherChangedTimes[e.FullPath] = now;
}
}
else
{
watcherChangedTimes.Add(e.FullPath, now);
}
#endregion
Thread.Sleep(5000);//等待5秒待文件释放
FileStream fs = null;
Assembly assembly = null;
try
{
Monitor.Enter(lockDllLoader);
fs = new FileStream(e.FullPath, FileMode.Open);
assembly = Assembly.Load(StreamToByte(fs));
writeLog("DLL" + e.FullPath + "was updated at " + DateTime.Now.ToString());
}
catch (Exception ex)
{
writeLog("DLL" + e.FullPath + "can't be updated at " + DateTime.Now.ToString() + ex.Message);
}
finally
{
if (fs != null)
{
fs.Close();
fs.Dispose();
}
Monitor.Exit(lockDllLoader);
}
if (assembly != null)
{
//更新AssemblyPool
assemblyPool[e.FullPath] = assembly;
}
}

 

其中setTimerPool方法用于加载现有DLL组件至缓存并并为每个Job启动一个Timer.

private void setTimerPool()
{
jobSettingPath = systemPath + @"\" + jobSettingName;
XmlDocument doc = new XmlDocument();
doc.Load(jobSettingPath);
XmlElement xeJobs = doc.DocumentElement;
foreach (XmlElement xeJob in xeJobs.GetElementsByTagName("Job"))
{
try
{
ExecuteParameter ep = getExecuteJobArgs(xeJob);
DateTime nextExeTime = CalculateTime.GetNextExecutionDateTime(ep.exeType, ep.exeDays, ep.exeTimes, DateTime.Now);
ep.nextExeTime = nextExeTime;
writeLog(ep.jobName + "\t First Execute Time is " + ep.nextExeTime.ToString("yyyy/MM/dd HH:mm:ss"));
TimerCallback tcb = new TimerCallback(execute);
Timer timer = new Timer(tcb, ep, getDueTime(nextExeTime), Timeout.Infinite);
timerPool.Add(ep.jobID, timer);
}
catch (Exception ex)
{
writeLog(xeJob.GetAttribute("Id") + " Fail to start \r\n" + ex.GetBaseException().Message);
}
}
}
  Timer组件执行的方法execute用于反射执行组件中特定的方法并重置Timer组件DueTime。
        /// <summary>
/// Timer执行方法
/// </summary> /// <param name="obj"></param> private void execute(object obj) { string exeTime = null; string assignedTime = null; ExecuteParameter ep = obj as ExecuteParameter; if (ep != null) { try { exeTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); assignedTime = ep.nextExeTime.ToString("yyyy/MM/dd HH:mm:ss"); DateTime nextExeTime = CalculateTime.GetNextExecutionDateTime(ep.exeType, ep.exeDays, ep.exeTimes, ep.nextExeTime); Timer timer = timerPool[ep.jobID]; timer.Change(getDueTime(nextExeTime), Timeout.Infinite); //每次执行后根据下次执行时间计算并改变Timer DueTime ep.nextExeTime = nextExeTime; //应用反射机制呼叫执行DLL中特定方法
FileStream fs = null; Assembly a = null; Type type = null; try { //载入Pool中Assembly,如果Pool中不存在,则添加进去
Monitor.Enter(lockFile); if (assemblyPool.ContainsKey(ep.fileName)) { a = assemblyPool[ep.fileName]; } else { fs = new FileStream(ep.fileName, FileMode.Open); a = Assembly.Load(StreamToByte(fs)); assemblyPool.Add(ep.fileName, a); } type = a.GetType(ep.typeName); } catch (Exception ex) { throw ex; } finally { if (fs != null) { fs.Close(); fs.Dispose(); } Monitor.Exit(lockFile); } //通过反射调用方法
                    object o = Activator.CreateInstance(type, ep.constructArgs);
Type[] argTypes = new Type[ep.methodArgs.Length];
for (int i = 0; i < argTypes.Length; i++)
{
argTypes[i] = typeof(string);
}
MethodInfo mi = type.GetMethod(ep.methodName, argTypes);
object objResult = mi.Invoke(o, ep.methodArgs);
writeLog(ep.jobID + "\t" + ep.jobName + "Run Successfully. \r\n\t\t\t Start to Execute at " + exeTime + " for Assigned Time at " + assignedTime + " \r\n\t\t\t" +
"Next Execution Time is " + ep.nextExeTime.ToString("yyyy/MM/dd HH:mm:ss"));
}
catch (Exception ex)
{
//write execute successfully message
try
{
string errorMsg = ep.jobID + "\t" + ep.jobName + "\t Fail to Run at " + exeTime + ".\r\n\t" + ex.Message +
"\r\n\t" + ex.GetBaseException().Message;
writeLog(errorMsg);
}
catch (Exception e)
{
string errorMsg = e.Message + "\r\n\t There is something wrong in the setting file, please check it.";
writeLog(errorMsg);
}
}
}
}

 

   需要注意的是:如果某个Job的配置档有所变更,比如说执行的时间点有变化,那么此job对应的Timer也必须重置,以按照最新的时间点执行。此动作可以利用windows Service的OnCustomCommand方法(参考C# 利用ServiceController控制window service)接收外部指令resetTimer.

        /// <summary>
/// Windows Service Reset Timer
/// </summary>
/// <param name="command">128-255</param>
protected override void OnCustomCommand(int command)
{
//YWindow service OnCustomCommand  Job Reset
if (command >= 128 && command < 255)
{
string cmdID = command.ToString();
System.Threading.Timer timer = timerPool.ContainsKey(cmdID) ? timerPool[cmdID] : null;
try
{
writeLog("Scheduled Job ID=" + cmdID + " Starts to Reset.");
if (timer != null)
{
timerPool.Remove(cmdID);
}
resetTimer(cmdID);
writeLog("Scheduled Job ID=" + cmdID + " Resets Successfully.");
if (timer != null)
{
timer.Dispose();
}
}
catch (Exception ex)
{
if (!timerPool.ContainsKey(cmdID))
{
timerPool.Add(cmdID, timer);
}
writeLog("Scheduled Job ID=" + cmdID + " Fail to Reset. \r\n\t" + ex.Message);
}
}
else if (command == 255)
{
GC.Collect();
}
}
        /// <summary>
/// Reset Timer
/// </summary>
/// <param name="commandID"></param>
private void resetTimer(string commandID)
{
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(jobSettingPath);
XmlElement xeJob = (XmlElement)xmlDoc.DocumentElement.SelectSingleNode("Job[@Id='" + commandID + "']");
ExecuteParameter ep = getExecuteJobArgs(xeJob);
DateTime nextExeTime = CalculateTime.GetNextExecutionDateTime(ep.exeType, ep.exeDays, ep.exeTimes, DateTime.Now);
ep.nextExeTime = nextExeTime;
writeLog(ep.jobName + "\t Execution Time is Reset to " + ep.nextExeTime.ToString("yyyy/MM/dd HH:mm:ss"));
TimerCallback tcb = new TimerCallback(execute);
Timer timer = new Timer(tcb, ep, getDueTime(nextExeTime), Timeout.Infinite);
timerPool.Add(ep.jobID, timer);
}
catch (Exception ex)
{
writeLog("Unable to reset timer " + commandID + "\r\n" + ex.GetBaseException().Message);
}
}

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载