Laravel项目Github Action执行失败:key生成时数据库连接拒绝
问题描述
我在Laravel项目中配置了如下GitHub Action工作流文件:
name: Laravel on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: laravel-tests: runs-on: ubuntu-latest steps: - uses: shivammathur/setup-php@15c43e89cdef867065b0213be354c2841860869e with: php-version: '8.1' - uses: actions/checkout@v3 - name: Copy .env run: php -r "file_exists('.env') || copy('.env.example', '.env');" - name: Install Dependencies run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist - name: Generate key run: php artisan key:generate - name: Directory Permissions run: chmod -R 777 storage bootstrap/cache - name: Create Database run: | mkdir -p database touch database/database.sqlite - name: Execute tests (Unit and Feature tests) via PHPUnit env: DB_CONNECTION: sqlite DB_DATABASE: database/database.sqlite run: vendor/bin/phpunit
同时我使用了GenreServiceProvider,代码如下:
$allGenres = Genre::where('isActive', 1)->orderBy('name')->get(); View::share([ 'allGenres' => $allGenres, ]);
在执行php artisan key:generate步骤时出现如下错误:
SQLSTATE[HY000] [2002] Connection refused (Connection: mysql, SQL: select * from `genres` where `isActive` = 1 and `genres`.`deleted_at` is null order by `name` asc)
注释GenreServiceProvider中的代码后项目可正常运行,但我希望它在GitHub Action中也能正常工作,请问该如何解决?
问题原因
Laravel服务提供者的boot方法会在应用启动阶段执行,而php artisan key:generate命令会触发完整的应用启动流程。此时GitHub Action环境中还未完成数据库配置:
- 执行
key:generate时,.env是从.env.example复制的默认配置,数据库连接为mysql,但Action环境没有启动MySQL服务 - SQLite数据库文件尚未创建,连接配置也未切换到SQLite
因此服务提供者启动时执行的数据库查询会因无法连接数据库而报错。
解决方案
方案1:延迟执行数据库查询(推荐)
不在服务提供者的boot方法中直接执行查询,改用视图合成器或懒加载,仅在实际使用数据时才执行查询:
// GenreServiceProvider.php public function boot() { // 视图合成器:仅当指定视图被渲染时才查询数据 View::composer(['layouts.app', 'your.target.views'], function ($view) { $view->with('allGenres', Genre::where('isActive', 1)->orderBy('name')->get()); }); // 或者全局懒加载:仅当视图调用$allGenres时才执行查询 // View::share('allGenres', function () { // return Genre::where('isActive', 1)->orderBy('name')->get(); // }); }
这种方式下,key:generate这类不涉及视图渲染的命令不会触发数据库查询,自然不会报错。
方案2:提前配置数据库环境变量
调整GitHub Action步骤顺序,在执行key:generate前就设置好SQLite连接配置,让应用启动时使用SQLite而非默认的MySQL:
# ... 原有步骤 ... - name: Copy .env run: php -r "file_exists('.env') || copy('.env.example', '.env');" # 添加此步骤,写入SQLite配置到.env - name: Set SQLite Database Config run: | echo "DB_CONNECTION=sqlite" >> .env echo "DB_DATABASE=database/database.sqlite" >> .env - name: Generate key run: php artisan key:generate # ... 后续步骤 ...
或者直接在Generate key步骤中注入环境变量:
- name: Generate key env: DB_CONNECTION: sqlite DB_DATABASE: database/database.sqlite run: php artisan key:generate
SQLite会自动创建不存在的数据库文件,不会出现连接拒绝的问题。
方案3:在服务提供者中判断执行环境
在服务提供者中判断当前是否为命令行环境,且不是测试相关命令,若是则跳过数据库查询:
// GenreServiceProvider.php use Illuminate\Support\Str; public function boot() { // 跳过命令行下的非测试命令 if (app()->runningInConsole() && !Str::contains(request()->server('argv')[0] ?? '', ['phpunit', 'test'])) { return; } $allGenres = Genre::where('isActive', 1)->orderBy('name')->get(); View::share([ 'allGenres' => $allGenres, ]); }
内容的提问来源于stack exchange,提问作者Taleh Orujov
相关产品推荐
相关产品推荐

