正确做法是为每个 Jenkins Job 隔离 COMPOSER_CACHE_DIR,通过设置环境变量使 composer 命令使用独占缓存路径,从而避免并发构建时因共享默认缓存导致的文件系统竞态问题。

Jenkins 部署时清 Composer 旧依赖缓存,核心不是跑 composer clear-cache,而是让每个 Job 拥有独占缓存目录,否则并发构建必然冲突。
为什么 Jenkins 上 composer clear-cache 总失败
多个 Pipeline Job 同时执行 composer clear-cache,而它们共享默认缓存路径(如 ~/.composer/cache),就会触发文件系统竞态:A 进程刚删掉 vcs/ 子目录,B 进程正往里面写 Git 裸仓库,结果报 Permission denied 或 Directory not empty。Windows 下更常见 Access is denied,本质是进程句柄未释放。clear-cache 实际是遍历并逐个 unlink 或 rmdir 四个子目录:repo/、files/、vcs/、http/,任意一个卡住,后续 Job 就可能复用损坏缓存。
正确做法:为每个 Jenkins Job 隔离 COMPOSER_CACHE_DIR
根本解法不是修 clear-cache,而是切断跨 Job 缓存共享。关键是在 Pipeline 脚本中显式设置环境变量,让所有 composer 命令自动使用独占路径:
- Linux/macOS:在
sh步骤前加export COMPOSER_CACHE_DIR="${WORKSPACE}/.composer-cache" - Windows(CMD):用
set COMPOSER_CACHE_DIR="%WORKSPACE%\.composer-cache" - 配合
sh 'rm -rf vendor'(或 Windows 对应命令),彻底断开vendor/与上一次缓存的关联 - 所有
composer install、composer update、composer clear-cache都会自动走这个路径,无需改命令
别缓存 vendor/ 目录本身
直接用 Jenkins cache 指令缓存 vendor/ 看似快,但极易出问题:
-
vendor/含用户权限、PHP 扩展绑定、符号链接等环境敏感信息 —— 上次构建用root,这次用jenkins用户,chown不及时就卡在Permission denied -
composer.lock更新后,旧vendor/缓存不会自动失效,composer install会跳过更新,导致依赖实际未升级 - 真正稳定可复用的是
COMPOSER_CACHE_DIR下的.zip/.tar.gz包和 dist hash,它与工作区无关,也不含环境绑定
部署脚本里要不要加 composer clear-cache
加了没坏处,但不是必须。只要每个 Job 的 COMPOSER_CACHE_DIR 是干净独占的,composer install 自然用新缓存;如果仍想保险,可在 install 前加一行:
composer clear-cache --no-interaction
--no-interaction 只跳过确认提示,不影响底层 IO,所以它解决不了竞态 —— 关键还是路径隔离。另外注意:CI 中若用了 Docker,镜像内也得设 COMPOSER_CACHE_DIR,否则容器间仍共享宿主机缓存。
最易被忽略的一点:Jenkins Job 的 Workspace 路径必须稳定且可写,不能靠 git clean -fdx 清掉整个 workspace 后再设缓存目录 —— 那样会导致 COMPOSER_CACHE_DIR 被误删,下次构建又 fallback 到全局路径。











