// 主调方法:遍历数据库,循环处理任务 public static void Run() { Utils.Output("计划任务服务端启动", "start"); UpdateDB(); // 程序首次运行,必须清空任务参数表(该表用于判断定时运行的任务结束时间) Dal.Default.ClearTimePara(); int second = RefreshDbSecond; while (true) { try { List <TaskItem> tasks = Dal.Default.GetAllTask(); List <Thread> threads = new List <Thread>(); if (tasks != null && tasks.Any()) { Utils.Output("找到" + tasks.Count.ToString() + "个任务"); // 读取任务执行前的进程清单,用于后面比对 var processes = ProcessItem.GetProcessesAndCache(); foreach (TaskItem task in tasks) { Thread thre = new Thread(RunTask) { IsBackground = true }; threads.Add(thre); thre.Start(task); } threads.ForEach(item => item.Join());// 阻塞到全部线程完成 RunTaskFinish(tasks, processes); } // 一轮完成,更新进程最后检查时间 Dal.Default.UpdateLastRuntime(); } catch (Exception exp) { Utils.Output("Main出错", exp); } Utils.Output("休眠" + second.ToString() + "秒"); Thread.Sleep(second * 1000); } // ReSharper disable once FunctionNeverReturns }
/// <summary> /// 返回所有进程信息 /// </summary> /// <returns></returns> static string GetProcesses() { var ret = new StringBuilder(10000); List <ProcessItem> processes = ProcessItem.GetProcessesAndCache(); // 按名称排序 foreach (var process in processes.OrderBy(item => item.name)) { ret.AppendFormat("{0}|||{1}|||{2}|||{4}|||{3}|||{5}|||{6}|/|/|/", process.pid.ToString(), process.name, process.memory.ToString(), process.memoryVirtual.ToString(), process.memoryPage.ToString(), process.createDate, process.commandLine); } return(ret.ToString()); }
static void RunTaskFinish(List <TaskItem> tasks, List <ProcessItem> processesBefore) { #if DEBUG var end = DateTime.Now; #endif var processesLater = ProcessItem.GetProcessesAndCache(false); foreach (TaskItem task in tasks) { var proBefore = ProcessHelper.FilterByPath(processesBefore, task.exepath); var proLater = ProcessHelper.FilterByPath(processesLater, task.exepath); var pidBefore = new StringBuilder(); var pidEnd = new StringBuilder(); foreach (var processItem in proBefore) { pidBefore.AppendFormat("{0},", processItem.pid.ToString()); } var taskNewPidFinded = false; foreach (var processItem in proLater) { if (task.NewPid > 0 && processItem.pid == task.NewPid) { taskNewPidFinded = true; } pidEnd.AppendFormat("{0},", processItem.pid.ToString()); } var noFindAndLog = (task.NewPid > 0 && !taskNewPidFinded); // Utils.Output(task.exepath+"\r\n"+pidBefore + "\r\n" + pidEnd + "\r\n" + task.NewPid, "aa"); // 运行时的进程不见了,或 前后的pid不同了 if (noFindAndLog || pidBefore.ToString() != pidEnd.ToString()) { // 更新任务的pid var newpid = proLater.Count > 0 ? proLater[0].pid : 0; Dal.Default.UpdateTaskProcessId(task.id, newpid); if (pidBefore.Length > 0) { pidBefore.Insert(0, "; 运行前pid:"); } if (pidEnd.Length > 0) { pidBefore.AppendFormat("; 运行中pid:{0}", pidEnd); } if (noFindAndLog) { pidBefore.AppendFormat("; 运行中pid{0} 已自动退出", task.NewPid.ToString()); } var pidMsg = task.runtype.ToString() + pidBefore; Dal.Default.AddTaskLog(task.exepath, pidMsg); } } #if DEBUG // 输出任务执行前后的进程情况 var procMsg = new StringBuilder(); // procMsg.AppendFormat("执行前:{0}\r\n", begin.ToString("HH:mm:ss.fff")); foreach (var processItem in processesBefore.OrderBy(item => item.exePath)) { procMsg.AppendFormat("{0} {1}\r\n", processItem.pid.ToString(), processItem.exePath); } procMsg.AppendFormat("执行后:{0}\r\n", end.ToString("HH:mm:ss.fff")); foreach (var processItem in processesLater.OrderBy(item => item.exePath)) { procMsg.AppendFormat("{0} {1}\r\n", processItem.pid.ToString(), processItem.exePath); } Utils.Output(procMsg.ToString(), "process"); #endif }
// 运行单个任务的主调方法, 注:因为是多线程执行,所以通过task.newpid 临时存储启动了的pid static void RunTask(object args) { try { TaskItem task = (TaskItem)args; // 防止出现 c:\\\\a.exe 或 c:/a.exe这样的路径,统一格式化成:c:\a.exe形式 task.exepath = Path.Combine(Path.GetDirectoryName(task.exepath) ?? "", Path.GetFileName(task.exepath) ?? ""); if (!File.Exists(task.exepath)) { // 可执行文件不存在, 更新任务运行状态 Dal.Default.UpdateTaskExeStatus(task.id, ExeStatus.NoFile); var tmpmsg = task.desc + " " + task.exepath + " 文件不存在"; Utils.Output(tmpmsg); return; } // 根据exe路径,查找运行中的进程 var processes = ProcessItem.GetProcessesAndCache().FindAll(item => item.exePath.Equals(task.exepath, StringComparison.OrdinalIgnoreCase)); ExeStatus status = ExeStatus.Unknown; // 判断进程状态,以更新表 DateTime now = DateTime.Now; StringBuilder msg = new StringBuilder(200); msg.AppendFormat(task.desc); // 每n分钟输出一次任务具体数据 if (now.Minute % 10 == 0 && now.Second <= RefreshDbSecond) { msg.AppendFormat("\r\n{0} {1} {2} {3} 已运行{4}次", task.runtype.ToString(), task.taskpara, task.exepath, task.exepara, task.runcount.ToString()); } switch (task.runtype) { case RunType.Stop: // 不启动,不停止 status = NoOperation(processes, msg); break; case RunType.Restart: // 重启 status = Restart(task, processes, msg); break; case RunType.StopAndWait1Min: // 停止并等1分钟重启 status = StopAndWait1Min(task, processes, msg); break; case RunType.ForceStop: // 强行停止 status = ForceStop(task, processes, msg); break; case RunType.Always: case RunType.OneTime: // 一直运行 或 只运行一次 status = AlwaysOrOneTime(task, processes, msg); break; case RunType.PerDay: case RunType.PerWeek: case RunType.PerMonth: // 定时运行 status = PerTime(task, processes, msg); break; } // 更新任务运行状态 Dal.Default.UpdateTaskExeStatus(task.id, status); } catch (Exception ex) { Utils.Output("运行任务时错误", ex); } }