Вопрос или проблема
Laravel 11, очереди Spatie для многопользовательской архитектуры не срабатывают
Я использую Laravel 11 с пакетом Spatie/Multi-tenancy для создания многоарендного SaaS-приложения.
Вот мой database.php
'tenant' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => null,
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'landlord' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => 'landlord_db',
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
multitenancy.php
'tenant_finder' => Spatie\Multitenancy\TenantFinder\DomainTenantFinder::class,
'switch_tenant_tasks' => [
// \Spatie\Multitenancy\Tasks\PrefixCacheTask::class,
Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class,
// \Spatie\Multitenancy\Tasks\SwitchRouteCacheTask::class,
],
'tenant_model' => Tenant::class,
'queues_are_tenant_aware_by_default' => true,
'tenant_database_connection_name' => 'tenant',
/*
* Имя подключения для доступа к базе данных арендодателя.
*/
'landlord_database_connection_name' => 'landlord',
файл env
DB_CONNECTION=tenant
DB_HOST=mysql_db
DB_PORT=3306
DB_DATABASE=landlord_db
DB_USERNAME=root
DB_PASSWORD=root
app.php, сообщите, пожалуйста, если промежуточное ПО правильное
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
api: __DIR__ . '/../routes/api.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->api(append: [
\Spatie\Multitenancy\Http\Middleware\NeedsTenant::class,
\Spatie\Multitenancy\Http\Middleware\EnsureValidTenantSession::class,
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Session\Middleware\StartSession::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
})
моя проблема в том, что очереди не срабатывают:
php artisan queue:work
Пожалуйста, дайте знать, если я что-то забыл или что-то упустил.
ошибка StackTrace:
[2024-09-20 20:05:25] local.ERROR: SQLSTATE[3D000]: Неверное имя каталога: 1046 База данных не выбрана (Соединение: tenant, SQL: select * from `jobs` where `queue` = high and ((`reserved_at` is null and `available_at` <= 1726862725) or (`reserved_at` <= 1726862635)) order by `id` asc limit 1 FOR UPDATE SKIP LOCKED) {"exception":"[object] (Illuminate\\Database\\QueryException(code: 3D000): SQLSTATE[3D000]: Неверное имя каталога: 1046 База данных не выбрана (Соединение: tenant, SQL: select * from `jobs` where `queue` = high and ((`reserved_at` is null and `available_at` <= 1726862725) or (`reserved_at` <= 1726862635)) order by `id` asc limit 1 FOR UPDATE SKIP LOCKED) at /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:825)
[stacktrace]
Ответ или решение
Проблема, с которой вы столкнулись, заключается в том, что система очередей в вашем приложении Laravel 11 с использованием пакета Spatie Multi-Tenancy не может корректно переключаться на соединение с арендатором для выполнения запросов к базе данных. Судя по предоставленному вами стеку ошибок, сообщение указывает на то, что база данных не выбрана для соединения tenant
.
Вот несколько шагов, которые помогут вам диагностировать и решить проблему:
1. Проверьте настройки соединения с базой данных
Убедитесь, что у вашего арендатор-соединения в config/database.php
, значение для database
корректно устанавливается на имя базы данных арендатора. В данный момент в конфигурации, вы указали database => null
в секции tenant
. Это, вероятно, является причиной ошибки "No database selected".
Примечание: Чтобы установить базу данных арендатора, нужно обновить код следующим образом:
'tenant' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => 'имя_вашей_базы_данных_арендатора', // замените на соответствующее значение
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
Также, необходимо убедиться, что имя базы данных арендатора устанавливается динамически при его создании или переключении.
2. Настройте очереди для арендаторов
Важно, чтобы ваш код правильно переключал арендаторское соединение перед выполнением задач в очереди. Убедитесь, что в вашем Job
используется правильная база данных арендатор при выполнении через очереди. Например:
class ExampleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
// Проверка текущего соединения
$tenant = app('currentTenant'); // Получите текущего арендатора
// Здесь должен быть код, который выполняется в контексте арендатора
}
}
3. Проверьте настройки multi-tenancy
Убедитесь, что вы правильно настроили пакет Spatie Multi-Tenancy для работы с очередями. В вашем файле config/multitenancy.php
, параметр queues_are_tenant_aware_by_default
установлен в true
, что правильно. Однако важно также удостовериться, что все задачи работают с текущей базой данных арендатора.
4. Обнаружение арендатора в очередях
При запуске php artisan queue:work
убедитесь, что правильный арендатор установлен в контексте, прежде чем вы обрабатываете задачи в очереди. Возможно, вам нужно будет использовать Tenant::find()
или другой способ, чтобы определить текущего арендатора до начала обработки заданий напрямую.
5. Настройка middleware
Ваши правила для middleware, кажется, в порядке. Однако, если вы добавите \Spatie\Multitenancy\Http\Middleware\SwitchTenantDatabase::class
в ваше API middleware, это обеспечит переключение базы данных арендатора.
Пример:
$middleware->api(append: [
\Spatie\Multitenancy\Http\Middleware\NeedsTenant::class,
\Spatie\Multitenancy\Http\Middleware\EnsureValidTenantSession::class,
\Spatie\Multitenancy\Http\Middleware\SwitchTenantDatabase::class, // Добавьте этот middleware
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Session\Middleware\StartSession::class,
]);
Заключение
Проверьте указанные шаги, чтобы убедиться, что у вас корректно настроено соединение с базой данных арендатора и процессы обработки очередей. Основная проблема связана с тем, что очередь пытается выполнить запрос к базе данных, которая не определена. Убедитесь в правильном переключении баз данных для каждой задачи в очереди. После внесения всех изменений, не забудьте протестировать их и перезапустить рабочие процессы очереди.