Skip to content

命令 ​

bash
bm2 serve                 # 登记并启动:生产模式(读 .env 与 .env.production)
bm2 dev                   # 同上,开发模式(读 .env 与 .env.development),单实例并跟随日志
bm2 stop <name>           # 停下,但留在册
bm2 remove <name>         # 退役:停下、注销、交还名字,日志保留
bm2 clean [--dry-run]     # 扫掉状态目录里的无主目录
bm2 remove <name> -f      # 退役并删除它的状态目录(含日志)
bm2 kill [-y]             # 杀掉全部项目并退出守护进程
bm2 list [name] [--json]  # 显示状态,可只看一个项目或输出 JSON
bm2 check                 # 校验当前目录的 bm2.toml
bm2 reload                # 换入新守护进程,应用继续运行
bm2 notify [target]       # 给本项目的目标发一条测试消息
bm2 upgrade               # 从下载站更新 bm2
bm2 version               # 打印版本

动词按层次分 ​

kill 属于守护进程。应用的生命周期由 stop、remove、clean 表达。kill 曾经也能退役单个项目,那让一个动词同时横跨两个层次——帮助文本自己也解释不清。

命令需要守护进程作用
serve需要,没有则自动拉起生产模式:登记、启动、写状态
dev需要,没有则自动拉起开发模式:登记、启动、写状态
stop <name>需要停实例,保登记
remove <name>需要停实例、注销、删登记与实例状态
clean不需要删掉状态目录下的无主目录
kill需要停掉全部项目并退出守护进程
list不需要没有守护进程时什么也不打印
check不需要只校验配置

serve 与 dev ​

在放着 bm2.toml 的目录里执行。两者只差一件事:读哪两个 .env 文件。serve 用 production,dev 用 development,监督行为完全相同——崩溃重启、内存上限、风暴预算、通知上报一视同仁。调试时的行为必须和线上一致,否则调试本身就没有意义。

它会校验配置、登记项目并启动。每次执行都是一次完整重启,所以改任何字段——实例数、端口、脚本——在下一次执行时生效。

dev 只跑一个实例。开发会话就是一个进程监听一个端口,所以配置里的 instances 在开发模式下不生效。这不是被悄悄丢掉——项目记录里带着模式,bm2 list --json 同时给出模式和实际实例数。

dev 启动后会在当前终端跟随实例日志,直到你按 Ctrl+C。日志照常落盘,跟随只是看着,不是牵着:应用继续运行,停止它用 bm2 stop <name>。脚本与 CI 里用 bm2 dev --no-follow,它跟 serve 一样发完请求就返回。

对已停止的项目再执行一次会清除停止标记,把它恢复起来。模式记在项目里,bm2 list --json 的每一行都带着它,bm2 reload 也不会把它弄丢。

名字已被另一份配置文件占用时拒绝登记,并报出占用者的路径与两条出路:改名,或先退役那一个。

stop <name> ​

优雅停止:先 SIGTERM,超过 stop_timeout_ms 后 SIGKILL。项目从 list 输出中消失,但仍留在册。

停止是持久的。守护进程重启或 bm2 reload 都不会把它带回来——只有 bm2 serve 或 bm2 dev 可以。

remove <name> ​

退役项目:停实例、注销项目、删掉它的登记与实例状态文件。日志保留,因为想翻日志的时刻通常发生在项目消失之后。

-f 额外删除 <state_dir>/<name>/,连日志一起。这个删除由 CLI 执行,并且只在项目从名册中消失之后——否则就是从还握着这个文件的进程脚下把日志抽走。

退役之后名字可以重新登记。新项目不继承上一代的任何东西:统计、重启历史、启动探测,都不继承。

clean [--dry-run] ​

扫描状态目录的第一层。没有 project.json 的目录就是无主目录:可能是硬删除留下的残骸,也可能来自另一台机器。

clean 逐条列出并删除,--dry-run 只列不动。它纯本地执行,不需要守护进程——状态目录换机器之后正是这种场景。

判据刻意保守——登记一定会先写 project.json——所以最坏结果是漏删某个目录,而不可能是删掉在册项目的日志。bm2 从未写过的目录会留在原地并给出说明。

kill ​

bash
bm2 kill -y     # 停掉全部项目、注销它们、退出守护进程

裸 bm2 kill 拒绝执行并说明原因,-y 是确认。带项目名是用法错误,提示会指路到 stop 与 remove。

对 bm2d 发送 SIGTERM(例如 systemctl restart)走的是同一条路径。

list ​

每个活跃或异常实例一行:PID、端口、启动模式(development / production)、执行模式(cluster / fork)、状态、内存、运行时长,以及项目的工作目录。被有意停止的实例不显示,restarting 与 errored 的实例保持可见,便于诊断。

--json 输出同样的机器可读数据;list 不需要守护进程,没有登记任何项目时就是一个空结果。

check ​

解析并校验当前目录的 bm2.toml,不触碰守护进程:字段约束、__VAR__ 展开、脚本是否存在。部署前跑一次很有用,它和 serve / dev 执行的是同一套检查。

reload ​

在不停止被托管应用的前提下换入新的 bm2d:旧守护进程分离,新守护进程以不变的 PID 收养仍在运行的实例。手动替换二进制之后用它——bm2 upgrade 会自动做这一步。

CLI 与守护进程会互相校验协议版本。版本不一致时直接提示执行 bm2 reload,而不是给一个查不到原因的错误。

notify ​

给本项目的通知目标发一条测试消息;写上目标名则只发给那一个。要在项目目录执行,因为目标来自那个项目的 bm2.toml。

异步行为 ​

start、stop、remove、kill 都是异步的:守护进程立即应答,CLI 轮询到操作真正结束。这样守护进程永远不会因为一个停止超时而阻塞——也是这些命令在结果真实发生之后才报告结果的原因。

如果守护进程意外崩溃并留下过期的端点文件,下一个 CLI 请求会短暂等待、清掉过期文件、拉起一个新的守护进程,并重试一次。

退出码 ​

码含义
0成功
1失败:守护进程拒绝、连不上,或目标不存在
2用法错误,在询问守护进程之前就被参数解析拦下