命令
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
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 | 用法错误,在询问守护进程之前就被参数解析拦下 |