laravel-multitenancy: Error dispatching queued jobs from artisan commands

Thanks for the great work, I have been using it for a short time and it has worked quite well except for putting a job in the queue when it is dispatched from an artisan command

Preconditions:

  • "php": "^7.4.0"
  • "laravel/framework": "^7.0",
  • Database for each tenant
  • jobs and jobs_failed tables are in each tenant database
  • Queue connection environment var QUEUE_CONNECTION=database
  • multitenancy config file has this value for queues 'queues_are_tenant_aware_by_default' => true
  • \Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class is registered in multitenancy file config

The command handler looks like:

class ImportUsers extends Command
{
    ... //removed to keep it short...
    public function handle(PeopleImporter $import)
    {
         ... //removed to keep it short
        try {
              DB::beginTransaction();
               user = User::updateOrCreate($data);
               if ($access->wasRecentlyCreated) {
		   // Push a queue job for publish a notification
		   dispatch(new PublishNewUser($access))->delay($this->delay);
		} else {
		  // Push a queue job for publish a notification
		   dispatch(new PublishUserChanges($access))->delay($this->delay);
		}
              DB::commit();
         } catch (\Throwable $exception) {
             DB::rollBack();
             Log::error($exception->getTraceAsString());
         }
         ... //removed to keep it short
    }
}

Using the tenants:artisan command wrapper, my command signature looks like:

php artisan tenants:artisan "app:import-users --file=files/imports/users.csv" --tenant=1

I have verified that the users are correctly registered in the correct database schema for the specified tenant, but I always get an error when trying to push the job to the queue.

The exception trace is:

Running command for tenant `Sandbox` (id: 1)...
---------------------------------------------------------

Starting import
===============

  0/10 [░░░░░░░░░░░░░░░░░░░░░░░░░░░░]   0%

Error: Call to a member function prepare() on null in /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php:458
Stack trace:
#0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(664): Illuminate\Database\Connection->Illuminate\Database\{closure}('insert into `jo...', Array)
#1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(631): Illuminate\Database\Connection->runQueryCallback('insert into `jo...', Array, Object(Closure))
#2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(465): Illuminate\Database\Connection->run('insert into `jo...', Array, Object(Closure))
#3 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(417): Illuminate\Database\Connection->statement('insert into `jo...', Array)
#4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Processors/Processor.php(32): Illuminate\Database\Connection->insert('insert into `jo...', Array)
#5 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(2771): Illuminate\Database\Query\Processors\Processor->processInsertGetId(Object(Illuminate\Database\Query\Builder), 'insert into `jo...', Array, NULL)
#6 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/DatabaseQueue.php(162): Illuminate\Database\Query\Builder->insertGetId(Array)
#7 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/DatabaseQueue.php(111): Illuminate\Queue\DatabaseQueue->pushToDatabase('publish-access-...', '{"uuid":"a7cd02...', Object(Carbon\Carbon))
#8 /var/www/html/vendor/laravel/framework/src/Illuminate/Queue/Queue.php(60): Illuminate\Queue\DatabaseQueue->later(Object(Carbon\Carbon), Object(App\Jobs\PublishAccessChanges), '', 'publish-access-...')
#9 /var/www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(171): Illuminate\Queue\Queue->laterOn('publish-access-...', Object(Carbon\Carbon), Object(App\Jobs\PublishAccessChanges))
#10 /var/www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(158): Illuminate\Bus\Dispatcher->pushCommandToQueue(Object(Illuminate\Queue\DatabaseQueue), Object(App\Jobs\PublishAccessChanges))
#11 /var/www/html/vendor/laravel/framework/src/Illuminate/Bus/Dispatcher.php(73): Illuminate\Bus\Dispatcher->dispatchToQueue(Object(App\Jobs\PublishAccessChanges))
#12 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Bus/PendingDispatch.php(134): Illuminate\Bus\Dispatcher->dispatch(Object(App\Jobs\PublishAccessChanges))
#13 /var/www/html/app/Imports/PeopleImport.php(104): Illuminate\Foundation\Bus\PendingDispatch->__destruct()
#14 /var/www/html/vendor/maatwebsite/excel/src/Sheet.php(275): App\Imports\PeopleImport->onRow(Object(Maatwebsite\Excel\Row))
#15 /var/www/html/vendor/maatwebsite/excel/src/Reader.php(111): Maatwebsite\Excel\Sheet->import(Object(App\Imports\PeopleImport), 2)
#16 /var/www/html/vendor/maatwebsite/excel/src/Transactions/NullTransactionHandler.php(14): Maatwebsite\Excel\Reader->Maatwebsite\Excel\{closure}()
#17 /var/www/html/vendor/maatwebsite/excel/src/Reader.php(115): Maatwebsite\Excel\Transactions\NullTransactionHandler->__invoke(Object(Closure))
#18 /var/www/html/vendor/maatwebsite/excel/src/Excel.php(146): Maatwebsite\Excel\Reader->read(Object(App\Imports\PeopleImport), 'files/imports/p...', 'Csv', 's3')
#19 /var/www/html/vendor/maatwebsite/excel/src/Concerns/Importable.php(37): Maatwebsite\Excel\Excel->import(Object(App\Imports\PeopleImport), 'files/imports/p...', 's3', 'Csv')
#20 /var/www/html/app/Console/Commands/ImportPeople.php(66): App\Imports\PeopleImport->import('files/imports/p...', 's3', 'Csv')
#21 [internal function]: App\Console\Commands\ImportPeople->handle(Object(App\Imports\PeopleImport))
#22 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(33): call_user_func_array(Array, Array)
#23 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(36): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#24 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(91): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
#25 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#26 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(592): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#27 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(134): Illuminate\Container\Container->call(Array)
#28 /var/www/html/vendor/symfony/console/Command/Command.php(258): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#29 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#30 /var/www/html/vendor/symfony/console/Application.php(911): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#31 /var/www/html/vendor/symfony/console/Application.php(264): Symfony\Component\Console\Application->doRunCommand(Object(App\Console\Commands\ImportPeople), Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#32 /var/www/html/vendor/symfony/console/Application.php(140): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#33 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(93): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#34 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(185): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\StringInput), Object(Illuminate\Console\OutputStyle))
#35 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(263): Illuminate\Console\Application->call('zintech:import:...', Array, Object(Illuminate\Console\OutputStyle))
#36 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php(261): Illuminate\Foundation\Console\Kernel->call('zintech:import:...', Array, Object(Illuminate\Console\OutputStyle))
#37 /var/www/html/vendor/spatie/laravel-multitenancy/src/Commands/TenantsArtisanCommand.php(56): Illuminate\Support\Facades\Facade::__callStatic('call', Array)
#38 /var/www/html/vendor/spatie/laravel-multitenancy/src/Commands/TenantsArtisanCommand.php(42): Spatie\Multitenancy\Commands\TenantsArtisanCommand->runArtisanCommandForTenant(Object(App\Models\Tenancy\Tenant), 'zintech:import:...')
#39 /var/www/html/vendor/laravel/framework/src/Illuminate/Support/Traits/EnumeratesValues.php(202): Spatie\Multitenancy\Commands\TenantsArtisanCommand->Spatie\Multitenancy\Commands\{closure}(Object(App\Models\Tenancy\Tenant), 0)
#40 /var/www/html/vendor/spatie/laravel-multitenancy/src/Commands/TenantsArtisanCommand.php(43): Illuminate\Support\LazyCollection->each(Object(Closure))
#41 [internal function]: Spatie\Multitenancy\Commands\TenantsArtisanCommand->handle()
#42 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(33): call_user_func_array(Array, Array)
#43 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(36): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#44 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(91): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
#45 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#46 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(592): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#47 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(134): Illuminate\Container\Container->call(Array)
#48 /var/www/html/vendor/symfony/console/Command/Command.php(258): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#49 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#50 /var/www/html/vendor/symfony/console/Application.php(911): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#51 /var/www/html/vendor/symfony/console/Application.php(264): Symfony\Component\Console\Application->doRunCommand(Object(Spatie\Multitenancy\Commands\TenantsArtisanCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#52 /var/www/html/vendor/symfony/console/Application.php(140): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#53 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(93): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#54 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#55 /var/www/html/artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#56 {main}# php artisan tenants:artisan "app:import-users --file=files/imports/users.csv" --tenant=1

The result is the same if exec the command without database transactions

Do you have any idea how I can solve it?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (1 by maintainers)

Most upvoted comments

@esalazarv in the big applications - when isolation could be needed - it’s better to avoid the database queue: you can use Redis or other (scalable?) queue solutions. Queues are differents than other data; you can change your queue logic any time without losing a single job.

No, im not using Redis for now, only database for this little project, but you are right the next step for a large app should be change to Redis or another service for now i don’t have many tenants that is why for now the solution that you helped me works well in my project, hopefully soon I will have to change to Redis, it would mean that everything is going very well with the project.

Thank you very much for your help.

Isn’t better to create only one jobs table in the landlord database? I think that’s more powerful: so, you can use Telescope to track all your jobs with no pain, for example.

Using that approach, you need to start a “queue:listen” for each tenant. I don’t know how many tenants you have, but for me, it’s a bit a wrong way.

Ok. Your jobs table is in landlord database? If so, change your database queue config following:

"driver" => "database",
"connection" => "landlord", // or your landlord connection name
"table" => "jobs",
"queue" => "default",
"retry_after" => 90,

It seems that somewhere the app loses the connection with the database. Can you supply a more accurate example?

You wrote php class ImportUsers... but the error starts from php App\Console\Commands\ImportPeople....

Finally, does your job implements the Spatie\Multitenancy\Jobs\TenantAware interface?