Sucha's Blog ~ Archive for February, 2020

20年2月2日 周日 22:22

mon_sched

好早之前,为了检测自己写的一个程序是否仍然存活,以及使用的内存、CPU 占用情况,我用 Lua 加上系统的 top 命令,整了一个 app_scheduler,将多个需要运行的程序做为一个进程组的概念组合起来,并用 Lua 的 os.execute() 实现切换工作目录,并将环境变量传递进去。

用 Lua 的好处是相当灵活,可以自定义任何时候,将程序拉起来,或者 kill 掉。但是缺点也很明显,这里周期性的用 top 命令,每次都得起一个 shell 进程,查看完信息后就退出了,有些浪费;而且要完成这样的一个控制结构,需要不少的 Lua 编程基础,还需要知道控制结构本身不同函数的作用才行。

后来看到了 mon,一个程序的 supervisor,只管一个进程,控制结构是相当的简单。我之前关于进程组概念的想法又冒了出来,想着将其改写为管理进程组,并且用 JSON 做为配置工具,最好还有类似 cron 控制周期性运行的能力。

后来就自己验证了一下,发现其实是可以的,然后就产生了 mon_sched,一个进程组 supervisor。使用 JSON 的控制结构也相当的简单,而且部分功能沿用了 mon 本来的配置:

{
        "name" : "mon_group",
        "logfile" : "mon_sched.log",
        "pidfile" : "mon_sched.pid",
        "daemon" : false,
        "mon1" : {
                "logfile": "log1.txt",
                "cmd": "example/program.sh",
                "attempts": 20,
		        "sleep": 10,
		        "on_error" : "",
		        "on_restart" : "",
                "cron": "* * * * 2"
        },
        "mon2" : {
                "cmd": "example/program2.sh",
                "logfile": "log2.txt",——
                "attempts": 30,
                "sleep": 5,
                "cron": "1 * * * *"
        }
}

上最外层的 name 是进程组的名称,日志、pid 文件路径,以及是否需要做为 daemon 运行;下面的是每个需要拉起程序的配置,cmd 是程序的路径以及参数,attempts 是重试次数,on_restart、on_error 是失败后重启、或者超过重试次数后的 shell 命令。

特别介绍一下 cron 参数,从左到右分别是分钟、小时,月日期、月份、周日期,并且支持部分域配置,比如

"0,30,45   */3     2,[4-9]     *       *"
# minius   hour    month_day   month   weak_day
# (0-59)   (0-23)  (1-31)      (0-11)  (0-6)

上面标示每个月的2号,以及4-9号,每3个小时的1、31、46分,运行一次程序。

话说为了实现这样的控制,存储结构用了 bitmap(还是觉得有些浪费),然后解析需要两层,第一层解析 blank、*、/、DIGIT 做为 TOKEN(其他可以认为是结束符,或者非法),然后比如 */3 这样的,需要保存上一个 TOKEN,用栈来实现,因为只有一层,其实用一个单独的变量比如 LAST_TOKEN 也是可以的;然后遇到空格、逗号、连字符后面的下一个数字 TOKEN,认为是一次识别结束,将位置相关的数字,设置到 bitmap 里面,话说重复的话也不管它了。

最后提一下,mon 本身就有说明不想用 awkward 的 DSL,然后参数都从命令行传递,而且为了保证稳定性,只管一个进程。相比之下,mon_sched 是都退回去了,用了 JSON 做为配置,然后管多个进程。

经验有限,更看中功能吧,也许是吃的苦还不够多。。。