Composer并发构建中clear-cache失败,因多Job共享COMPOSER_CACHE_DIR导致文件系统竞态;根本解法是为每个Job隔离缓存路径,通过设置COMPOSER_CACHE_DIR指向WORKSPACE子目录实现独占。

composer clear-cache 在 Jenkins 并发构建中为什么会失败
多个 Pipeline Job 同时执行 composer clear-cache,而它们共享同一个 COMPOSER_CACHE_DIR(比如默认的 ~/.composer/cache),就会触发文件系统级竞态:删除操作非原子,A 进程刚删掉 http/ 子目录,B 进程正往里面写响应缓存,结果报 Permission denied 或 Directory not empty。Windows 下更常见 Access is denied,本质是句柄未释放。
-
composer clear-cache实际是遍历并逐个unlink或rmdir四个子目录:repo/、files/、vcs/、http/ - 并发时任意一个子目录被卡住(尤其
vcs/里大体积 Git 裸仓库),后续 Job 就可能复用损坏缓存 -
--no-interaction完全不解决这个问题——它只跳过确认提示,不影响底层 IO 冲突
如何为每个 Jenkins Job 隔离 Composer 缓存路径
根本解法不是修 clear-cache,而是让每个 Job 拥有独占缓存目录。关键是在 Pipeline 中显式设置 COMPOSER_CACHE_DIR,指向 ${WORKSPACE} 下的子路径,避免跨 Job 读写冲突。
- Linux/macOS:在
environment或sh前加export COMPOSER_CACHE_DIR="${WORKSPACE}/.composer-cache" - Windows:用
set COMPOSER_CACHE_DIR="%WORKSPACE%\.composer-cache" - 所有
composer命令(包括install、update、clear-cache)都会自动使用该路径 - 配合
sh 'rm -rf vendor'(或 Windows 对应命令),彻底切断 vendor 和缓存之间的跨 Job 关联
为什么不能直接缓存 vendor/ 目录
直接用 Jenkins cache 指令缓存 vendor/ 看似快,但极易引发权限错、lock 文件漂移、PHP 版本不一致等隐性故障。真正稳定复用的是 Composer 下载层的包缓存,不是解压后的代码树。
-
vendor/是构建产物,含用户权限、PHP 扩展绑定、符号链接等环境敏感信息 - 上一次构建用 root,这次用 jenkins 用户,
chown不及时就会卡在Permission denied -
composer.lock更新后,旧vendor/缓存不会自动失效,composer install会跳过更新,导致依赖实际未升级 - 稳定缓存点只有
$HOME/.composer/cache(或你指定的COMPOSER_CACHE_DIR),它存的是 .zip/.tar.gz 包和 dist hash,与工作区无关
多项目共用全局缓存时的折中方案
如果必须复用下载包(比如节省带宽),全局缓存可以保留,但必须确保 clear-cache 不再出现——它和并发构建天然互斥。
- 禁用所有 Pipeline 中的
composer clear-cache,改用定期运维脚本清理(如每天凌晨单次执行) - 全局缓存路径(如
/var/lib/jenkins/composer-cache)需由 agent 启动时固化:在 systemd service 或 Docker entrypoint 里写死export COMPOSER_CACHE_DIR=... - Pipeline 中只调用
composer install --prefer-dist,它会自动查全局缓存,无需额外命令 - 若某项目需强制重下,用
composer install --no-cache,而不是清全局缓存
真正麻烦的从来不是缓存没命中,而是缓存“看似命中却行为异常”——比如 vendor 权限错、lock 版本滞后、HTTP 缓存损坏。隔离 COMPOSER_CACHE_DIR 是最轻量也最可靠的破局点,其他方案都绕不开这个前提。


















