- 角色
- 个人项目
- 状态
- 私有/本地
- 版本
- local tag v0.5.0
- 关键结果
- 类型化 findings 与受控操作,落在同一份权威的 launchd 状态上。
- 技术栈
- RustCLImacOS
是什么
ghrunners 会找出一台 Mac 上所有 actions-runner
(跑 GitHub Actions 任务的执行器),交叉核对 launchctl
域状态、进程树、.runner JSON、worker 日志,以及
(可选的)GitHub API。观测核心——status、
describe、doctor、logs——会把
查出来的问题整理成一条条类型化的 finding;另外还有个独立、受控的
control 子命令,动的也是同一份状态。它是个私有的本地
工具,它具体对应哪个快照,写在下面的「证据」里。
要解决的问题
Mac 上一台 你自己运行、用来执行 GitHub Actions 任务的机器,区别于 GitHub 托管的云端 runner——操作系统、网络,以及任务之间保留什么,都由你掌控。 悄无声息地挂掉时,线索是散落
各处的:macOS 的系统服务管理器——负责启动、停止、监督后台服务(大致相当于 Linux 上的 systemd)。 记着域和上次退出状态,进程树才知道 worker
是不是真活着,安装目录用 0700 权限把配置挡在外面,
而 GitHub API 才知道任务到底有没有真正派到这台机器上。你 SSH 上去一点点拼,
可最顺手的修法——重启 runner——恰恰最危险:一条不小心的命令,
就可能干掉正在跑的构建,或者把它 bootstrap 进错误的 launchd 域。
约束与关键决策
单次观测,基于权威状态。它不跑监控在任务之间常驻后台的程序。ghrunners 刻意反其道而行——一次性运行:跑一次、做完动作就退出,不保留长期状态。,每次都是无状态调用,去解析 launchctl
print 的正文——读它不需要 sudo。所以哪怕
是非 root 调用,它报出来的运行态和上次退出状态也是权威的,而不是
拿 ps 猜的。代价:单次运行也意味着
没有持续监控、没有历史趋势——想要快照就跑一次,或者交给 cron
定时跑。
部分输出,而不是一遇错就停。runner 的安装
目录在别人的用户名下、权限 0700,严格一点的工具
没有 sudo 就直接报错退出。这里换成优雅降级:
PID - 和 REPO ? 不算错误,读不动的
路径变成一条 Unreadable finding,而不是直接崩掉;
与此同时,state 列仍然从不需要 sudo 的 print 正文
里读,所以保持权威。代价:表格里每一个空着的格子,工具都得设计好它的含义、
解释清楚——到底是权限不够,还是真的没有——而且少了
sudo,输出就不那么完整。
受控的 control,绑在它观测到的状态上。最顺手的
下一步——start / stop / restart——恰恰是危险的那一步,所以
control(bootstrap / unload / restart)的目标,是从
观测核心那份权威状态里解析出来的,而不是随手敲
launchctl。--dry-run 只打印解析出来的
命令,并不执行;除了 DoubleLoaded 情况下的 unload,
--domain 一律按用法错误拒绝(其余每个 verb 的目标
都是确定的,再去覆盖只会搞乱);而在某个 verb 可能干掉正在
运行的 Runner.Worker 之前,必须显式传
--yes。代价:要多记一串前置条件和
参数,而且有些直接用 launchctl 照样能跑的命令,工具
会故意拒掉。
类型化 findings 和稳定的退出码,而不是大段日志。
「这个 runner 健康吗」需要机器读得懂的答案,所以把问题归纳成
13 种带严重度的类型化 findings——doctor 只打印
可操作的 warn / error,每条带一行
fix:——而且 status 或 doctor
一看到 warning 或 error,进程就以 1 退出,于是
ghrunners doctor >/dev/null || mail … 能当 cron
健康检查用。代价:每一条 finding 都是一份
类型化契约,要定义、要触发、要标严重度、要给修法——是一套需要
维护的分类目录,而不是随手写的自由文本。
证据
私有快照 local tag v0.5.0——没有可查看的公开源码。
支撑这些说法的,是真正跑起来的功能:status、
describe、doctor、logs
和受控的 control 现在都能用,背后是一份 13 种
类型化 findings 的目录(从 LoadedNotRunning、
OrphanListener 到 DoubleLoaded、
Unreadable),外加 cron 友好的退出码、JSON 输出,
以及每个控制动作都给的 --dry-run 预览。这套能力是
一步步落地的:v0.2 加了控制 verb,v0.3 让运行态从 print 正文里
读出来、变得权威,v0.4 加了 doctor 巡检和 OrphanListener。
下一步
下一步还没完全敲定;候选项包括把 GitHub API 接得更深,以及把 真实机器上冒出来的边角情况沉淀成新的 findings。等仓库能公开 访问,再加源码链接。
它不是什么
- 不是 runner 安装或注销工具。
- 不是 daemon 或持续监控器。
- 不是 fleet 管理——控制是单 runner、受控的,不是批量编排。
- 不支持 Linux 或 Windows。
- 私有 / 本地——目前还不是公开源码项目。