- 角色
- 个人项目
- 状态
- 私有、本地
- 快照
- 本地 tag v0.5.0
- 关键结果
- 类型化 findings 与受控操作,都基于同一份权威的 launchd 状态。
- 技术栈
- RustCLImacOS
是什么
ghrunners 会找出一台 Mac 上所有 actions-runner
(跑 GitHub Actions 任务的执行器),交叉核对 launchctl
域状态、进程树、.runner JSON、worker 日志,以及(可选的)GitHub API。观测核心——status、
describe、doctor、logs——会把查出来的问题整理成一条条类型化 findings;另外还有个独立、受控的
control 子命令(verb),动的也是同一份状态。这是私有、本地工具;对应的快照写在下面的「证据」里。
要解决的问题
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,输出就不那么完整。
受控操作,绑在它观测到的状态上。最顺手的下一步——start / stop / restart——恰恰是危险的那一步,所以
control(bootstrap / unload / restart)的目标,是从观测核心那份权威状态里解析出来的,而不是随手敲 launchctl。
--dry-run 只打印解析出来的命令,并不执行。--domain 一律按用法错误拒绝,唯一的例外是 DoubleLoaded 情况下的 unload——其余每个子命令的目标都是确定的,再去覆盖只会打乱状态。而在某个子命令可能中断正在运行的 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 加了控制子命令,v0.3 让运行态从 print 正文里读出来、成为权威,
v0.4 加了 doctor 巡检和 OrphanListener。
下一步
候选范围,不作承诺:更深的 GitHub API 信息补全,以及把真实机器上冒出来的边角情况沉淀成新的 findings。仓库若变为公开可访问,再补源码链接。
它不是什么
- 不是 runner 安装或注销工具。
- 不是守护进程或持续监控器。
- 不做机群管理——控制面向单个 runner,受控,不做批量编排。
- 不是 Linux 或 Windows 上的工具。
- 私有、本地——目前不是公开源码项目。