使用C#开发计划任务调度服务
在系统运维中常常需要定期去跑一些计划任务,比如扫描服务器监控其性能、检查SQL Server作业是否正常、监控MQ队列是否存在堵塞现象等。如果使用Windows计划任务调度,一来管理起来就比较松散,二来如需更改计划任务的配置就必须登录到服务器上进行修改,造成很大的不便。因此笔者在实际工作中自行开发计划任务调度服务来处理这些任务,将调度周期、任务配置等经常需要修改的配置信息保存到数据库中,并开发一个前台界面进行维护和管理。
一、基本结构
计划任务调度服务使用插件的方式处理各类不同的计划任务,插件必须继承自服务框架提供的MonitorTask抽象类,并在数据库中注册任务名、调度周期等信息,这样就可以由该服务调度执行。为方便起见,要求任务名、插件的dll文件名、插件对象的类型名必须一致,各插件都放在同一个命名空间MonitorTask下。
在工作中,各类监控任务主要有3种配置:
1.调度周期,以xml形式保存在数据库中。
2.监控项,以键值对的方式保存在数据库中。
3.基本不会修改的一些个性化配置,以xml文件方式保存在插件同级目录下,名称与插件名一致。
二、插件的父类
所有插件都必须继承自MonitorTask抽象类,这里之所以使用抽象类而不使用接口是考虑到可以在这个抽象类中实现一些共性的东西,如参数配置的加载、错误日志的记录等。
public abstract class MonitorTask
{
protected XElement _configElement;
public List<Schedule> Schedules;
protected List<MonitorSetting> MonitorSettings;
private bool _isRunning = false; protected MonitorTask()
{
LoadParameters();
} public void Execute()
{
try
{
if (CouldExecute())
{
_isRunning = true;
ExecuteTask();
ExecuteLog();
}
}
catch (Exception e)
{
new LogText(AppDomain.CurrentDomain.BaseDirectory + @"log.log").Write(GetType().Name + "插件执行异常", e.ToString());
}
finally
{
_isRunning = false;
}
} private bool CouldExecute()
{
if (_isRunning || Schedules == null)
{
return false;
}
foreach (var schedule in Schedules)
{
if (schedule.TimeUp())
{
return true;
}
}
return false;
} protected abstract void ExecuteTask(); private void ExecuteLog()
{
if (ConfigManagement.GetConfig().GetAppSetting("ExecuteLog") == "")
{
new LogText(AppDomain.CurrentDomain.BaseDirectory + @"executelog.log").Write(GetType().Name + "插件执行完毕");
}
} protected void LoadParameters()
{
if (File.Exists(GetConfigFile()))
{
_configElement = XElement.Load(GetConfigFile());
LoadXMLParameters();
}
LoadMonitorSettings();
} private string GetConfigFile()
{
return AppDomain.CurrentDomain.BaseDirectory + GetType().Name + ".xml";
} protected virtual void LoadXMLParameters()
{
} protected void LoadMonitorSettings()
{
MonitorSettings = new List<MonitorSetting>();
string sql = "SELECT Name, Value FROM MonitorTaskSetting WHERE MonitorTaskID IN (SELECT ID FROM MonitorTask WHERE Name = '" + GetType().Name + "')";
using (SqlDataReader reader = SqlAssist.Select("SOMP", sql))
{
while (reader.Read())
{
MonitorSettings.Add(new MonitorSetting(reader.GetString(), reader.GetString()));
}
}
}
}
在开发计划任务插件时只需要继承该类,并实现ExecuteTask方法就行了。在这里ConfigManagement.GetConfig().GetAppSetting(string name)、new LogText(string filename).Write(string value)以及SqlAssist.Select(string dbname, string sql)这三个方法都是笔者在开发过程中自行封装的,为了避免重复劳动,一看名字就该知道这些方法的作用吧。
二、任务调度周期
在MonitorTask抽象类中还有一个List<Schedule>,用于保存任务调度的周期,Schedule也是一个抽象类,该抽象类主要由3个方法:
public static List<Schedule> CreateSchedule(XElement element)
该方法根据保存在数据库中的xml数据构建出Schedule。
public abstract bool TimeUp()
由子类实现该方法,判断是否已到达需要调度任务的时间。
public abstract XElement ToXML()
由子类实现该方法,用于将任务调度周期序列化成xml,便于保存到数据库中。
三、管理类
该类主要根据数据库中的配置利用反射构建出相应的计划任务对象,并将其缓存在Dictionary对象里避免多次构建,同时创建线程执行这些插件。
public static class MonitorTaskManagement
{
private static Dictionary<string, MonitorTask> _tasks = new Dictionary<string, MonitorTask>(); private static MonitorTask GetMonitorTask(string fileName, string taskType, XElement element)
{
Assembly assembly = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + fileName);
Type type = assembly.GetType(taskType);
if (type.IsSubclassOf(typeof(MonitorTask)))
{
MonitorTask task = Activator.CreateInstance(type) as MonitorTask;
task.Schedules = Schedule.CreateSchedule(element);
return task;
}
else
{
throw new Exception("程序集" + taskType + "有误。");
}
} private static MonitorTask GetMonitorTask(string taskName, XElement element)
{
MonitorTask task;
if (_tasks.ContainsKey(taskName))
{
task = _tasks[taskName];
}
else
{
task = GetMonitorTask(taskName + ".dll", "MonitorTask." + taskName, element);
_tasks.Add(taskName, task);
}
return task;
} public static void ExecuteTask()
{
string sql = "SELECT Name, Schedule FROM MonitorTask WHERE Enable = 1";
using (SqlDataReader reader = SqlAssist.Select("SOMP", sql))
{
while (reader.Read())
{
try
{
MonitorTask task = GetMonitorTask(reader.GetString(), XElement.Parse(reader.GetString()));
Thread childThread = new Thread(task.Execute);
childThread.IsBackground = true;
childThread.Start();
}
catch (Exception e)
{
new LogText(AppDomain.CurrentDomain.BaseDirectory + @"log.log").Write(reader.GetString() + "插件异常", e.ToString());
}
}
}
}
}
使用C#开发计划任务调度服务的更多相关文章
- 【开源】OSharp3.3框架解说系列:开发计划与进度
OSharp是什么? OSharp是个快速开发框架,但不是一个大而全的包罗万象的框架,严格的说,OSharp中什么都没有实现.与其他大而全的框架最大的不同点,就是OSharp只做抽象封装,不做实现.依 ...
- Fragment开发计划
Fragment是什么 Fragment正如字面意思所言是碎片,所以这是一个管理碎片时间的应用程序.目前考虑的是先在Android上实现,如果IOS的合作伙伴靠谱可以交给他做,如果不靠谱就等Andro ...
- 【NetDIY智能主控】开发计划
经过一个轮回,硬件开发.硬件创业又被推到了历史的前台. 面向低端.初级的硬件爱好者,以Arduino和81单片开发板为核心的开源硬件越来越深入人心,参与的人群越来越多,相关硬件和周边模块也越来越便宜. ...
- PHP 开发社区微信服务号实战图解
本博文就月初刚上线的微信服务号,图文进行总结分享给大家. 去年年底,我所在的团队讨论要开发微信号,话题由此拉开: 原来有一个3年前注册的微信号,但是后台操作无法从“订阅号”变更为“服务号”,随即找腾讯 ...
- 开发工具及服务年度大奖评选 I Bugtags 荣获最具成长潜力奖
作为全球最大中文 IT 社区和服务平台.中国最大技术管理者平台的 CSDN 在中国北京总部举办了一场 2015 年开发工具及服务年度大奖评选活动,此次活动目的在于推动开发服务及工具质量的提升,提高行业 ...
- 引擎设计跟踪(九.14.2h) 开发计划
以后的开发计划: 完善game runtime code, 跑简单的demo目前只有编辑器的运行流程, 没有游戏/demo流程, 图形的测试主要在编辑器上测试, 现在需要测试android系统的图形, ...
- 基于SpringBoot开发一个Restful服务,实现增删改查功能
前言 在去年的时候,在各种渠道中略微的了解了SpringBoot,在开发web项目的时候是如何的方便.快捷.但是当时并没有认真的去学习下,毕竟感觉自己在Struts和SpringMVC都用得不太熟练. ...
- Topshelf 一个简化Windows服务开发的宿主服务框架
Topshelf是 基于.net框架开发的宿主服务框架.该框架简化了服务的创建,开发人员只需要使用 Topshelf编写一个控制台程序,就能安装为Windows服务.之所以这样原因非常简单:调试一个控 ...
- Xianfeng轻量级Java中间件平台:一期开发计划
关于Xianfeng轻量级Java中间件平台,考虑到需要控制开发周期,通过分期开发的方式来实现一些基础的.常用的功能,这样有利于跟踪开发计划.一期的开发计划,主要实现的目标如下: 系统架构: 1.确定 ...
随机推荐
- android 7.0变化
一.加强版的低电耗模式 条件:1未插电源:2屏幕关闭:(N与6.0的区别就在于N在手机非静止时也可进入低电耗模式) 作用过程及方式:1充电状态:2屏幕关闭一定时间:进入一级低电限制:关闭网络,推迟CP ...
- linux的压缩命令
gzip: Linux压缩保留源文件的方法: gzip –c filename > filename.gz Linux解压缩保留源文件的方法: gunzip –c filename.gz > ...
- ubuntu 14.04 下通过apt-get 安装jdk
Installing default JRE/JDK sudo apt-get update sudo apt-get install default-jre sudo apt-get install ...
- SQLSERVER不带JOIN的语句与带JOIN语句的区别
//1.连接两个表查询 SELECT * FROM table1 t1,table2 t2 //2.连接两个表查询 SELECT * FROM table1 join table2 on table1 ...
- Linux-Rsync服务器/客户端搭建实战
一.需求 每晚汇总各机器的操作日志,同步到主服务器进行日志分析. 二.基础知识 rsync 分为服务器端.客户端,服务器端搭建比客户端辛苦一些(也是很简单). rsync 服务器是指以 deamon ...
- 安装sql2008的时候选择的是Windows身份验证,现在我想用sql server身份验证,我应该到哪儿设置呢
本文档整理自网络,存粹用作笔记. 安装过程中,SQL Server 数据库引擎可以设置为 Windows 身份验证模式或 SQL Server 和 Windows 身份验证模式. 本文介绍如何在安装后 ...
- 转载:scala中:: , +:, :+, :::, ++的区别
原文链接:https://segmentfault.com/a/1190000005083578 初学Scala的人都会被Seq的各种操作符所confuse.下面简单列举一下各个Seq操作符的区别. ...
- 用msbuild构建应用
msbuild是微软提供的一个用于生成应用程序的平台,你可以通过一个xml配置文件来控制和处理你的软件工程.它也集成到了vs里面,它不依赖于vs. xml配置(架构)的组成元素: 项目文件 属性 项 ...
- 自动化运维:网站svn代码上线更新(flask+saltstack)
阶段性总结: 跌跌撞撞的用了一周左右的时间做完了网站自动升级功能,中间遇到了很多的问题,也学到了很多,在此做一个总结. 1.整体架构: 后台:nginx+uwsgi #nginx提供w ...
- 免费提供UG、ProE二次开发、定制化开发服务
免费提供UG.ProE二次开发,定制开发服务. 拥有六年UG.ProE二次开发经验,相关项目经验. 从事过智能设计.计算机图形学相关研究. 联系方式: QQ:1787326383 微信号:begtos ...