MPDF多并发进程下创建缓存目录报错问题求助
解决mPDF 8.x多进程并发下缓存目录冲突问题
问题分析
你遇到的mkdir(): File exists错误,本质是多进程同时操作同一全局缓存目录引发的竞态条件——进程A刚创建完目录,进程B未及时感知仍执行创建操作,触发报错。mPDF默认复用全局缓存目录,高并发场景下这类冲突必然出现。
解决方案
1. 为每个进程分配独立缓存目录(推荐)
你提出的基于随机字符串创建私有缓存目录是可行且直接的解决办法。初始化mPDF时,通过tempDir参数指定进程专属缓存路径:
// 生成唯一的进程级缓存目录 $uniqueCacheDir = sys_get_temp_dir() . '/mpdf_cache_' . uniqid(mt_rand(), true); // 提前创建目录(确保父目录存在) if (!is_dir($uniqueCacheDir)) { mkdir($uniqueCacheDir, 0777, true); } // 初始化mPDF时指定私有缓存目录 $mpdf = new \Mpdf\Mpdf([ 'debug' => true, 'allow_output_buffering' => true, 'tempDir' => $uniqueCacheDir // 核心配置项 ]); // 原有业务代码保持不变 $mpdf->allow_charset_conversion = true; $mpdf->charset_in = 'utf-8'; $mpdf->setFooter('{PAGENO} de {nbpg}'); $mpdf->WriteHTML($html); $pdf_gen = $mpdf->Output('', \Mpdf\Output\Destination::STRING_RETURN); // 可选:PDF生成完成后清理当前进程的缓存目录,避免磁盘占用过高 array_map('unlink', glob($uniqueCacheDir . '/*')); rmdir($uniqueCacheDir);
2. 修复mPDF缓存目录创建的竞态问题(进阶)
若无法修改业务代码,可直接修改mPDF的Cache.php文件,给目录创建逻辑增加存在性检查和排他锁,避免竞态:
打开/var/app/current/vendor/mpdf/mpdf/src/Cache.php,找到第49行的mkdir调用,替换为以下代码:
// 替换原mkdir逻辑,增加锁机制避免多进程冲突 if (!is_dir($path)) { // 用临时文件做排他锁 $lockFile = $path . '.lock'; $lockHandle = fopen($lockFile, 'w'); if (flock($lockHandle, LOCK_EX)) { // 再次检查目录是否已被其他进程创建 if (!is_dir($path)) { mkdir($path, 0755, true); } flock($lockHandle, LOCK_UN); } fclose($lockHandle); @unlink($lockFile); // 清理锁文件 }
注意:这种修改属于vendor目录定制化改动,后续Composer更新mPDF时会被覆盖,需做好备份或通过补丁工具(如cweagans/composer-patches)维护。
方案对比
- 独立缓存目录:实现简单,完全隔离进程间缓存操作,无竞态风险,适合高并发场景;仅需额外处理缓存目录清理,避免磁盘占用过高。
- 修复mPDF源码:无需修改业务逻辑,但依赖vendor目录改动,维护成本较高,适合无法调整业务代码的场景。
内容的提问来源于stack exchange,提问作者André DLC
相关产品推荐
相关产品推荐

