-
-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error dispatching queued jobs from artisan commands #76
Comments
It seems that somewhere the app loses the connection with the database. Can you supply a more accurate example? You wrote Finally, does your job implements the |
Hi @masterix21 c) : Yes, all jobs implements Create a basic comand php artisan make:command ImportUsers Use this code for the command: <?php
namespace App\Console\Commands;
use App\Jobs\PublishNewUser;
use App\Models\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class ImportUsers extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:import-users';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
try {
DB::beginTransaction();
$faker = \Faker\Factory::create();
$user = User::create([
'name' => $faker->name,
'email' => $faker->email,
]);
dump($user->toArray());
dispatch(new PublishNewUser($user))->delay(now()->addSeconds(10));
DB::commit();
} catch (\Throwable $exception) {
DB::rollBack();
Log::error($exception->getTraceAsString());
}
}
} Create a basic Job
Use this code for the Job: <?php
namespace App\Jobs;
use App\Models\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Spatie\Multitenancy\Jobs\TenantAware;
class PublishNewUser implements ShouldQueue, TenantAware
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* @var User
*/
protected $user;
/**
* Create a new job instance.
*
* @param User $user
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
Log::info($this->user->toJson());
}
} Run command: php artisan tenants:artisan app:import-users --tenant=1 The console output: Running command for tenant `Sandbox` (id: 1)...
---------------------------------------------------------
array:5 [
"name" => "Sharon Ernser"
"email" => "darian.bahringer@friesen.net"
"updated_at" => "2020-07-10T16:33:33.000000Z"
"created_at" => "2020-07-10T16:33:33.000000Z"
"id" => 21
]
All done! Then new user record is now in database, but job is not in If you remove Running command for tenant `Sandbox` (id: 1)...
---------------------------------------------------------
array:5 [
"name" => "Lloyd Stehr"
"email" => "maureen.conn@hotmail.com"
"updated_at" => "2020-07-10T16:58:21.000000Z"
"created_at" => "2020-07-10T16:58:21.000000Z"
"id" => 22
]
Error
Call to a member function prepare() on null
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:458
454| if ($this->pretending()) {
455| return true;
456| }
457|
> 458| $statement = $this->getPdo()->prepare($query);
459|
460| $this->bindValues($statement, $this->prepareBindings($bindings));
461|
462| $this->recordsHaveBeenModified();
+12 vendor frames
13 app/Console/Commands/ImportUsers.php:52
Illuminate\Foundation\Bus\PendingDispatch::__destruct()
+34 vendor frames
48 artisan:37
Illuminate\Foundation\Console\Kernel::handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
|
Using tinker, can you post here the output of Thanks |
For # php artisan tinker
Psy Shell v0.10.4 (PHP 7.4.7 — cli) by Justin Hileman
>>>
>>> config('queue.connections.'. config('queue.default'));
=> [
"driver" => "database",
"table" => "jobs",
"queue" => "default",
"retry_after" => 90,
]
>>> Using tinker for a tenant # php artisan tenants:artisan tinker --tenant=1
Running command for tenant `Sandbox` (id: 1)...
---------------------------------------------------------
Psy Shell v0.10.4 (PHP 7.4.7 — cli) by Justin Hileman
>>> config('queue.connections.'. config('queue.default'));
=> [
"driver" => "database",
"table" => "jobs",
"queue" => "default",
"retry_after" => 90,
]
>>> |
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, |
No, each tenant has its own database and has its own jobs table, maybe with a SwicthQueueConnectionTask for solve this? |
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. |
I put the job tables in each database because I was planning to keep most of the data isolated and to be able to explicitly handle job queues by tenant, and that the landlord had their own job table too, but I didn't know the recommended approach is that everything is managed in the landlord Let me try that approach, because with a SwicthQueueConnectionTask I get the same results. |
@masterix21 For now I think it is a solution but it would be nice to be able to completely isolate it. Thank you so much for your support. |
@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. |
@esalazarv, can be closed the issue? It is solved, or is there something else? |
Hi @masterix21, The alternative of putting all the jobs in the landlord database works for me, but I don't know if you would consider an issue when dispatching a job from the artisan command, if not then yes, the issue can be closed. Thanks. |
I think my issue (#82) is related. Scheduled jobs (App/Console/Kernel) don't seem to be tenant aware when executed from the scheduler or commands (schedule:run). Chris |
Closing this one, as it seems to have been answered. |
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",
jobs
andjobs_failed
tables are in each tenant databaseQUEUE_CONNECTION=database
'queues_are_tenant_aware_by_default' => true
\Spatie\Multitenancy\Tasks\SwitchTenantDatabaseTask::class
is registered in multitenancy file configThe command handler looks like:
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:
The result is the same if exec the command without database transactions
Do you have any idea how I can solve it?
The text was updated successfully, but these errors were encountered: