.Net自写Task进程监控程序

简介: 需求:线上运行的job,有时间可能因为数据库异常、内存不足或者是内部其他异常导致整个进程退出,是偶发事件,但是如果进程停止,业务数据没处理积压起来,会影响业务。

需求:线上运行的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正常运行多了一层保障。

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





相关文章
|
5月前
|
网络协议 Linux
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
Linux查看端口监听情况,以及Linux查看某个端口对应的进程号和程序
739 2
|
5月前
|
Linux Python
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
linux上根据运行程序的进程号,查看程序所在的绝对路径。linux查看进程启动的时间
78 2
|
29天前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
86 13
|
3月前
.NET 4.0下实现.NET4.5的Task类相似功能组件
【10月更文挑战第29天】在.NET 4.0 环境下,可以使用 `BackgroundWorker` 类来实现类似于 .NET 4.5 中 `Task` 类的功能。`BackgroundWorker` 允许在后台执行耗时操作,同时不会阻塞用户界面线程,并支持进度报告和取消操作。尽管它有一些局限性,如复杂的事件处理模型和不灵活的任务管理方式,但在某些情况下仍能有效替代 `Task` 类。
|
4月前
|
Ubuntu 持续交付 API
如何使用 dotnet pack 打包 .NET 跨平台程序集?
`dotnet pack` 是 .NET Core 的 NuGet 包打包工具,用于将代码打包成 NuGet 包。通过命令 `dotnet pack` 可生成 `.nupkg` 文件。使用 `--include-symbols` 和 `--include-source` 选项可分别创建包含调试符号和源文件的包。默认情况下,`dotnet pack` 会先构建项目,可通过 `--no-build` 跳过构建。此外,还可以使用 `--output` 指定输出目录、`-c` 设置配置等。示例展示了创建类库项目并打包的过程。更多详情及命令选项,请参考官方文档。
260 11
|
3月前
|
XML 存储 安全
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
C#开发的程序如何良好的防止反编译被破解?ConfuserEx .NET混淆工具使用介绍
137 0
|
3月前
|
安全 API C#
C# 如何让程序后台进程不被Windows任务管理器强制结束
C# 如何让程序后台进程不被Windows任务管理器强制结束
82 0
|
4月前
|
Python
惊!Python进程间通信IPC,让你的程序秒变社交达人,信息畅通无阻
【9月更文挑战第13天】在编程的世界中,进程间通信(IPC)如同一场精彩的社交舞会,每个进程通过优雅的IPC机制交换信息,协同工作。本文将带你探索Python中的IPC奥秘,了解它是如何让程序实现无缝信息交流的。IPC如同隐形桥梁,连接各进程,使其跨越边界自由沟通。Python提供了多种IPC机制,如管道、队列、共享内存及套接字,适用于不同场景。通过一个简单的队列示例,我们将展示如何使用`multiprocessing.Queue`实现进程间通信,使程序如同社交达人般高效互动。掌握IPC,让你的程序在编程舞台上大放异彩。
31 3
|
4月前
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
|
4月前
|
自然语言处理 C# 图形学
使用dnSpyEx对.NET Core程序集进行反编译、编辑和调试
使用dnSpyEx对.NET Core程序集进行反编译、编辑和调试