.Net自写Task进程监控程序

Posted 真爱无限

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.Net自写Task进程监控程序相关的知识,希望对你有一定的参考价值。

需求:线上运行的job,有时间可能因为数据库异常、内存不足或者是内部其他异常导致整个进程退出,是偶发事件,但是如果进程停止,业务数据没处理积压起来,会影响业务。为了能自动监控并启动这种意外停止的进程,写了一个程序监控,每分种检查一遍,然后自动处理,实际上是非常有用的。


贴代码如下:

//主要逻辑

            var runday = DateTime.Today;
            ConfigFile.Instanse.fileName = CommonFunctions.GetAbsolutePath("Kulv.YCF.KeepTaskRun.ini");//获取配置文件绝对路径
            string ExeFile = "";
            string ServiceName = "";
            var configIndex = 1;
            RunTaskAgain(() =>
            
                while (true)
                
                    try
                    
                        ExeFile = ConfigFile.Instanse["ExeFile" + configIndex];
                        if (string.IsNullOrEmpty(ExeFile)) break;
                        Logger.Info("………………………………………………………… ExeFile" + configIndex + " Start……………………………………………………………");//写日志到文本文件中
                        ServiceName = ConfigFile.Instanse["ServiceName" + configIndex];

                        var isRun = CommonFunctions.IsProgramRun(ExeFile);//判断exe是否在运行的进程中
                        if (DateTime.Today != runday)
                        
                            runday = DateTime.Today;
                        

                        Logger.Info(string.Format("ExeFile:0,ServiceName:1", ExeFile, ServiceName));
                        if (isRun)
                        
                            Logger.Info("程序正在运行中");
                        
                        else
                        
                            Logger.Info(string.Format("程序未运行,尝试启动服务"));
                            var startResult = CommonFunctions.RunCmd(string.Format("sc start \\"0\\"", ServiceName));//通过cmd命令启动服务
                            var regex = new Regex("(\\r\\n)+");
                            startResult = regex.Replace(startResult, "$1");//多个换行替换成一个
                            Logger.Info("\\r\\n" + startResult);
                            if (startResult.Contains("失败") == false)
                            
                                Logger.Info(string.Format("启动服务成功!"));
                            
                            var phonestr = ConfigFile.Instanse["CellPhone" + configIndex];
                            FinanceApiInvoke.ApiDomain = ConfigFile.Instanse["MapApiAddress" + configIndex]; ;
                            if (string.IsNullOrEmpty(phonestr))
                            
                                Logger.Info(string.Format("短信接收人配置" + configIndex + "为空!"));
                            
                            else if (string.IsNullOrEmpty(FinanceApiInvoke.ApiDomain))
                            
                                Logger.Info(string.Format("短信发送API配置" + configIndex + "为空!"));
                            
                            else
                            
                                DateTime dt = DataCache.GetCache<DateTime>("LastSendMsgTime");//用缓存,5分钟内只发一次短信
                                if ((DateTime.Now - dt).TotalMinutes >= 5)
                                

                                    var phones = phonestr.Split(new char[]  ',' , StringSplitOptions.RemoveEmptyEntries);
                                    List<SMSForSendIModel> msgList = new List<SMSForSendIModel>();
                                    foreach (var phone in phones)
                                    
                                        msgList.Add(new SMSForSendIModel()
                                        
                                            CompanyId = CompanyEnum.YaoChufa,
                                            Phone = phone,
                                            SendBy = "KeepTaskRun",
                                            UserId = 0,
                                            TemplateCode = "NOTICE-COMMON0",
                                            UserType = UserType.SystemUser,
                                            Content = string.Format("库存服务YCF_STOCK_TASK处于停止状态,监控程序已在尝试启动服务,如果自动启动失败,需要人工处理!如正在发布请忽略此信息。")
                                        );
                                    
                                    var sendRet = FinanceApiInvoke.SendSmsToWithEncryptionBatch(msgList, true);//通过api提交要发的短信给内部系统
                                    Logger.InfoFormat("短信返回:0", JsonUtility.ToJson(sendRet));
                                    DataCache.Set<DateTime>("LastSendMsgTime", DateTime.Now, 60 * 5);
                                    Logger.InfoFormat("job监控发短信成功");
                                

                            
                        
                        Logger.Info("……………………………………………………………ExeFile" + configIndex + " End………………………………………………………………");
                        configIndex++;
                    
                    catch (Exception ex)
                    
                        Logger.Info("配置" + configIndex + ",ErrorMessage:" + ExceptionMessage.GetOnlyMessage(ex));
                    
                
            , Logger, this.GetType().Name);

//配置文件-Kulv.YCF.KeepTaskRun.ini

[配置1]
ExeFile1=D:\\Task\\StockTask\\YCF.Stock.Task.exe
ServiceName1=YCF_Stock_Task
CellPhone1=15920522222,15920522223
MapApiAddress1=
[配置2]
ExeFile2=D:\\Task\\StockTask\\YCF.Stock.Task2.exe
ServiceName2=YCF_Stock_Task2
CellPhone2=15920522222,15920522223
MapApiAddress2=
[配置3]
ExeFile3=D:\\Task\\StockTask\\YCF.Stock.Task3.exe
ServiceName3=YCF_Stock_Task3
CellPhone3=15920522222,15920522223
MapApiAddress3=

//判断方法:

        /// <summary>
        /// 判断程序是否正在运行
        /// </summary>
        /// <param name="exefile">The exefile.</param>
        /// <returns></returns>
        public static bool IsProgramRun(string exefile)
        //D:\\FinancePartTask\\Kulv.YCF.Task.exe
            Process[] processes = Process.GetProcesses();
            string FileName = "";
            bool ret = false;
            Process toKill = null;
            foreach (Process thisproc in processes)
            
                try
                
                    FileName = thisproc.MainModule.FileName;
                    if (FileName == exefile)
                    
                        toKill = thisproc;
                        break;
                    
                
                catch// (Exception ex)
                
                    //FileName = "不能访问";
                
            
            try
            
                if (toKill != null)
                
                    ret = true;
                
                else
                
                    ret = false;
                
            
            catch// (Exception ex)
            
                ret = false;
            
            return ret;
        

        /// <summary>
        /// 运行传入的cmd命令
        /// </summary>
        /// <param name="cmd">cmd语句</param>
        /// <returns></returns>
        public static string RunCmd(string cmd, string cmdCurrentDir = null)
        
            string ret = "";
            if (!string.IsNullOrEmpty(cmdCurrentDir)) cmd = "cd /d " + cmdCurrentDir + " & " + cmd;
            cmd = cmd + " &exit"; //说明:不管命令是否成功均执行exit命令,否则当调用ReadToEnd()方法时,会处于假死状态
            using (var p = new Process())
            
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
                p.StartInfo.RedirectStandardInput = true; //接受来自调用程序的输入信息
                p.StartInfo.RedirectStandardOutput = true; //由调用程序获取输出信息
                p.StartInfo.RedirectStandardError = true; //重定向标准错误输出
                p.StartInfo.CreateNoWindow = true; //不显示程序窗口
                p.Start(); //启动程序

                //向cmd窗口写入命令
                p.StandardInput.WriteLine(cmd);
                p.StandardInput.AutoFlush = true;

                p.WaitForExit(); //等待程序执行完退出进程
                ret = p.StandardOutput.ReadToEnd();
                p.Close();
            
            return ret;
        



这样,业务task异常退出之后,程序会自动启动服务,对task正常运行多了一层保障。

有人会问,监控程序本身也会异常退出呀,根据运行情况来看,没有异常退出过,因为程序内部与数据库等等都没交互,不会引发不明情况的异常退出,所以基本上不会异常退出。





以上是关于.Net自写Task进程监控程序的主要内容,如果未能解决你的问题,请参考以下文章

“在WINDOWS启动时不显示此信息或启动系统配置实用程序”(高悬赏)

Laravel 框架中的火基并从 DB 获取此信息

Unix系统编程()进程和程序

为啥我不能将此信息从一个反应组件推送到另一个?

获取我的 RAM 的制造商名称(WMI 没有获得此信息)

如何将此信息存储在qt中?数组列表?