直接删除缓存锁文件即可:rm -f ~/.composer/cache/repo.packagist.org.lock;若仍报错,需检查并终止占用进程(lsof +D ~/.composer/cache),或在 CI 中使用 COMPOSER_CACHE_DIR=$(mktemp -d) 隔离缓存目录并降低并发数至2。

composer install 卡在 “Cache is locked” 怎么办
这不是网络或权限问题,而是 Composer 的全局缓存目录(~/.composer/cache)被另一个进程占用了写锁,常见于 CI 并发构建、本地多终端同时运行 composer install 或中断后残留锁文件。
- 先确认是否真有锁:运行
ls -la ~/.composer/cache/*.lock,若存在repo.packagist.org.lock或类似文件,说明锁未释放 - 直接删锁文件即可:
rm -f ~/.composer/cache/repo.packagist.org.lock(注意不是删整个 cache 目录) - 如果删了还报锁,可能是进程仍在占用——查一下:
lsof +D ~/.composer/cache或fuser -v ~/.composer/cache,杀掉相关 PID - CI 场景下建议加前置清理:在
composer install前插入rm -f ~/.composer/cache/*.lock,避免 job 间干扰
为什么 --no-cache 不起作用
--no-cache 只跳过读缓存,不绕过写锁逻辑;Composer 在下载前仍会尝试获取缓存锁来维护元数据一致性。所以即使你加了这个参数,只要缓存目录存在且有并发写入意图,锁冲突照常发生。
- 真正禁用缓存行为需组合使用:
COMPOSER_CACHE_DIR=/dev/null composer install - 或者彻底隔离缓存路径:
COMPOSER_CACHE_DIR=$(mktemp -d) composer install,每个 job 独享缓存目录 - 注意:
/dev/null方式会导致重复下载包,仅适合单次构建或调试;生产 CI 更推荐后者 + 清理临时目录
高并发 CI 中频繁触发缓存锁的根源
根本不在 Composer 本身,而在于默认配置允许最多 10 个并发 HTTP 下载请求,所有请求共用同一缓存锁文件。当多个 job 同时启动,它们几乎同时尝试 acquire 同一个锁,超时排队后形成“假死”。
- 必须降并发数:
composer config -g repos.packagist.org.concurrent-downloads 2 - 确保镜像源配置含
"canonical": false,否则多镜像无效,仍打向单一地址加剧锁争用 - 换源后务必
composer clear-cache,否则旧元数据继续走官方源,锁还在原地 - 验证生效:
composer config -g | grep concurrent应输出"concurrent-downloads": 2
缓存锁和 composer.lock 锁是两回事
很多人混淆这两者:flock ./composer.lock 控制的是项目级依赖写入串行化,而 Cache is locked 是 Composer 自身全局缓存的读写协调机制。前者防 vendor 冲突,后者防元数据损坏;修复一个不能代替另一个。
- 如果你在 CI 脚本里同时用了
flock .git -c 'composer install'和遇到缓存锁报错,说明两个锁没解耦——应分别处理 - 推荐结构:
rm -f ~/.composer/cache/*.lock && flock .git -c 'COMPOSER_CACHE_DIR=$(mktemp -d) composer install' - 特别注意 WSL2 或 NFS 挂载路径下,
flock对缓存目录可能完全失效,此时只能靠COMPOSER_CACHE_DIR隔离 + 降并发


















