
说起我这回动手的契机,挺偶然的。我最近一直在琢磨着怎么把手头的几个小工具整合起来,让它们能互相通信,但又不希望引入太复杂的中间件,什么MQ、Redis啥的,一想到那些部...
说起我这回动手的契机,挺偶然的。我最近一直在琢磨着怎么把手头的几个小工具整合起来,让它们能互相通信,但又不希望引入太复杂的中间件,什么MQ、Redis啥的,一想到那些部署和维护,我就头大。
我手头有几个Python写的后台脚本,处理一些数据清洗和定时任务,跑在几台不同的Linux机器上。平时我都是靠SSH一个个连上去,手动跑脚本,或者用最原始的Crontab定时。这玩意儿要是任务多了,根本没法集中管理,日志也散得哪里都是。
我心想能不能搞个特别轻量级的机制,让我能从一个中心点,下发指令到其他机器,并且能实时看到执行结果。一开始我考虑过ZeroMQ,但总觉得那个网络模型对我这个需求来说有点过了,我需要的只是简单的请求-响应,或者说,简单的任务推送。
我决定从最简单的开始,先搭一个服务端,就是那个“中心点”。我选了*,主要是因为写个简单的Web服务特别快,几行代码就能跑起来。我找了个开源的库,专门用来做一些事件广播,但核心逻辑我都是自己写的。

我定义了我的通信协议,就是JSON格式的数据包。一个包里头得有任务ID、目标机器的标识、执行的命令字符串,还有个时间戳。我甚至都没用HTTPS,全程HTTP POST请求,反正在内网里折腾,速度和安全对我来说没那么重要,稳定就
服务端搭建起来后,我开始写那个接收指令的客户端脚本。我没用Go或者Python的协程,我直接用了Python的subprocess模块,用一个无限循环去监听一个本地端口。这个监听端口,就是我用来接收来自服务端的“点名”信号。
接收到指令后,代码会解析那个JSON包,然后直接把命令字符串当成Shell命令来执行。执行完后,把标准输出和标准错误都捕获起来,打包成新的JSON响应包,再POST回给服务端。
刚跑起来的时候,我发现了个大问题:我发了指令,但不知道它到底跑完了没有。程序卡在等待subprocess返回中,如果哪个命令卡死了,我的客户端就一直卡着,服务端那边也收不到响应,就是超时丢弃。

我立刻修改了客户端逻辑。不再让主线程一直阻塞等待。我引入了多线程,每接收到一个任务请求,就立刻启动一个新线程去执行那个命令。这样主线程就能马上向服务端回复一个“收到,正在处理中”的状态信息。
等子线程执行完任务后,它自己负责把最终结果打包,然后异步地发给服务端。这样一来,状态管理就好多了。我还给每个任务加了一个简单的超时机制,如果线程跑了超过预设时间还没返回,我就强制结束它,然后把“超时”这个状态报告上去。
东西跑起来后,我发现光靠Postman或者命令行测试不行,我总得有个地方能直观地看到所有机器的状态。我找了另一个老旧的Flask项目,干脆给它加了个界面,就当做一个临时的控制台。
我让Flask后端去定时轮询我那个*服务端的状态接口,把收到的任务列表和机器状态实时展示出来。这个界面做得很简陋,一个表格,机器名、心跳时间、当前执行的任务ID。能看就行,我没花心思美化。
我点点鼠标,输入一条命令,比如“df -h”,点“执行”,几秒钟后,表格里对应的机器状态就从“空闲”变成了“处理中”,再过一会儿,表格更新,机器又变回“空闲”,我点开那个任务ID,就能看到刚才的磁盘使用情况了。
整个系统跑下来,比我预想的要稳定一些。它虽然没有复杂的认证授权,没有持久化存储,但对于我这种需要临时、快速地在几台机器上跑一些小脚本的需求来说,这个自制的KAREZ系统(我就这么随便叫它的名字),还真挺好用,至少比我来回SSH方便多了。