因为Composer install本身不加锁且不校验写入状态,多进程并发读取同一composer.lock后各自安装,导致vendor/不一致或部分包漏装;必须用flock等文件锁串行化操作,并禁用自动update,统一通过人工审核PR更新lock。

composer install 为什么在并发部署中会装出不同依赖?
因为 composer install 本身不加锁,也不校验写入时的文件状态。多个进程同时读取同一份 composer.lock,各自解析、下载、写入 vendor/,但没人管“别人是不是也在改”。更糟的是:如果某个进程中途被中断(如 CI 超时 kill),vendor/ 可能半途而废,而 composer.lock 还在——下次 install 就可能跳过某些 require-dev 包,或降级已安装的包。
典型现象包括:
-
The lock file does not contain the required package "xxx"—— 不是 lock 缺包,而是 install 过程中某进程漏装了 - CI 构建成功但线上运行报
Class not found—— 因为两个 job 同时 install,一个装了symfony/http-client,另一个没装(因锁文件被覆盖前已读完) -
composer.lock的content-hash没变,但packages数组顺序错乱 —— Git 自动换行或编辑器格式化导致 JSON 结构不一致,后续composer update --lock会整块重写
如何用 flock 正确保护 composer install?
flock 不是可选优化,是必须手段。它锁的是文件描述符,不是路径字符串,所以 ./composer.lock 必须存在且可写,否则锁无效。
实操要点:
- 只锁
composer.lock,不要锁composer.json—— 后者不参与 install 逻辑,锁它没意义 - 命令要写成
flock ./composer.lock -c 'composer install --no-interaction --no-progress',不能把composer install放在flock外面 - Linux/macOS 可用;Windows 下需改用 PowerShell 的
Get-FileLock或进程级互斥量,flock不可用 - CI 中更稳妥的做法是锁整个项目目录,例如
flock .git -c 'composer install',避免多个 job 同时操作同一仓库
为什么禁止自动化执行 composer update?
composer update 是唯一真正危险的操作:它会重写 composer.lock,且不校验当前 lock 是否已被他人修改。并发跑多个 update,等于让多个人同时重画同一张地图——结果必然是覆盖、丢失、哈希错乱。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
正确流程必须是人工驱动:
- 所有依赖变更(增删改
composer.json)都走 PR - PR 中触发
composer update xxx或composer update --lock,生成新 lock 并提交 - CI 脚本里只允许
composer install,且带flock - 绝对禁用
composer update --no-interaction类自动更新脚本,它等同于放弃版本控制
config.lock = true 能防什么?不能防什么?
"config": {"lock": true} 是 Composer 2.2+ 的硬性开关,作用很明确:只要 composer.json 和 composer.lock 的 content-hash 不匹配,composer install 就直接报错退出。
它能防:
- 改了
composer.json却忘记composer update就直接install - 同事删了
composer.lock后自己install导致本地环境漂移
它不能防:
-
composer.lock被并发写入损坏(仍会报错,但错误来源是文件内容而非哈希) - 不同 PHP 版本下平台约束解析差异(如
php: "^8.1"在 8.1.22 和 8.1.25 下可能选不同分支) - 手动编辑
composer.lock后保留合法 JSON 但破坏语义(比如删掉某个require-dev的 entry,content-hash仍对,但 install 会漏装)
真正难的不是加配置,而是让所有人理解:composer.lock 不是生成物,它是和 composer.json 平级的源码——改它,要像改业务逻辑一样走评审、测试、合入流程。漏一次提交,后面排查的时间远超三分钟确认 lock 是否已 push。

















