// 主调方法:遍历数据库,循环处理任务
        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
        }
Beispiel #2
0
        /// <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);
            }
        }