Symfony部署Heroku遇SQL连接拒绝,clearCache脚本执行失败求助
这个问题我之前帮朋友排查过,本质是Heroku编译阶段和运行阶段的环境差异搞的鬼——Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache在build阶段执行时,Symfony的缓存清理过程会尝试连接数据库,但Heroku的编译阶段(build phase)根本不会分配数据库连接,只有到release或运行阶段才会有真实的数据库可用,所以直接触发了SQLSTATE[HY000] [2002] Connection refused的错误,导致编译失败。
下面给你几个靠谱的解决办法,你可以按需尝试:
1. 把缓存清理移到release阶段执行(最推荐)
Heroku支持把需要运行环境的脚本放到release阶段,这个阶段已经有数据库连接了。你需要修改composer.json里的scripts配置:
- 先把
symfony-scripts里的clearCache移除 - 新增一个
release脚本专门处理缓存清理
修改后的脚本部分大概是这样:
"scripts": { "symfony-scripts": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" ], "post-install-cmd": [ "@symfony-scripts" ], "post-update-cmd": [ "@symfony-scripts" ], "release": [ "php bin/console cache:clear --no-warmup", "php bin/console cache:warmup" ] }
Heroku会自动识别composer.json里的release脚本,在部署的release阶段执行,这样缓存清理时就能正常连接数据库了。
2. 给编译阶段设置临时的空数据库连接
如果你一定要在编译阶段执行缓存清理,可以给Heroku的build环境设置一个不会触发真实连接的数据库参数,比如用内存SQLite:
打开Heroku命令行,执行:
heroku config:set SYMFONY_DATABASE_URL=sqlite:///:memory: --app 你的应用名称
这样编译阶段Symfony会用内存SQLite当数据库,不会去连真实的PostgreSQL/MySQL,也就不会报连接拒绝了。放心,运行阶段Heroku会自动注入真实的DATABASE_URL环境变量,覆盖这个临时设置。
3. 给clearCache脚本加--no-warmup参数
试试在composer.json里给clearCache脚本加上--no-warmup,避免缓存预热时连接数据库:
"symfony-scripts": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache --no-warmup", // 其他脚本... ]
不过这个方法要看Symfony版本,有些旧版本的ScriptHandler可能不支持传递参数,你可以先测试下能不能生效。
另外提一句,你添加的ext-apcu依赖要确保Heroku能正确识别——只要你是通过composer require ext-apcu添加的,Heroku编译时会自动安装这个扩展,一般不会有问题,但如果还是有问题,可以检查下composer.json里的require部分是不是正确声明了。
内容的提问来源于stack exchange,提问作者symguy

