背景:问题从哪来
很多集成里会用 Node 跑一层「侧车」(sidecar),底下再接 matter.js 做配网、订阅和控制。侧车启动时往往要指定一块持久化目录:配网信息、Fabric、会话状态等都会落在磁盘上。
若集成方没有显式配置这块目录,常见实现会退回到一个相对安装位置的默认路径——例如「在侧车脚本所在目录往上几级,下面再建一个 .matter」。这在单机、单进程、自己本机调试时通常能跑通,所以容易被忽略。
但一旦进入多实例场景(同一台机器上跑多个进程、多个容器副本、或同一镜像起多份),大家往往共用同一份侧车安装目录。这时默认路径会变成:所有实例指向同一块磁盘上的同一目录。后果不是「路径漂不漂亮」,而是数据层互相踩踏:两个控制器进程同时写同一套状态,轻则异常、重则配网/Fabric 损坏。这和「相对路径是否相对当前工作目录」无关——只要多个进程解析到同一个物理目录,就是同一个坑。
思路:把「存储根目录」提升为一等配置
核心原则可以概括成三句话:
- 默认路径可以保留(兼容老用户、本地开发),但不能假装它能安全地服务多实例。
- 生产与多实例场景必须能指定「只属于本实例」的根目录,且最好是绝对路径,避免随工作目录、启动方式变化。
- 配置入口要离启动侧车最近:谁拉起 Node 子进程(例如 Rust 适配层),谁就应该能把「存储路径」传进去;侧车进程里再读环境变量或参数,在未显式传 matter.js 的
--storage-path时,优先用这份配置,再退回默认。
这样设计的好处是:运维可以用环境变量或编排系统(systemd、K8s、Docker)按实例注入不同路径;库的使用者也可以在配置结构体里显式赋值,不依赖全局环境。
环境变量与配置结构:给集成方一个稳定契约
对外约定一个清晰命名的环境变量(例如专门表示「Matter 控制器持久化根目录」),并在库的默认配置里若设置了就读取、去空白、否则视为未设置。同时在本库的 SidecarConfig(或等价配置)上增加可选字段,与上述环境变量同源或可被代码覆盖。
拉起子进程时,在各种 IPC 模式(标准输入输出、WebSocket、Unix 域套接字等)下一致地把该环境变量传给子进程,避免「某种模式忘了带参」的隐性 bug。
侧车内部逻辑调整为:若命令行里还没有 --storage-path,则先看环境变量;有则用(可对路径做规范化,例如解析为绝对路径),没有再走原来的默认目录,并确保目录存在。这样手动调试时仍可给 Node 直接加 --storage-path,与自动化注入互不冲突。
这个问题本质是并发与隔离:多个控制器实例不能共享同一份 matter.js 本地状态。解决办法不是纠结「相对还是绝对」四个字,而是把存储根目录变成显式、可按实例区分的配置,并从拉起侧车的一方稳定传递到 Node。默认路径可以留着方便开发,但多实例与生产必须靠显式路径隔离