Laravel Job - No handler registered for command - laravel

I tried to get a simple job running exactly like the example in the Laravel Documentation - https://laravel.com/docs/5.2/queues#writing-job-classes - but I get this error: "No handler registered for command [App\Jobs\SendReminderEmail]".
I followed the instructions to make the jobs table and even the failed_jobs table and have the exact example code.
I assured that the handle() function is there so I don't know what else can be missing.
Regards.
Update with code:
First I used the class in the Laravel example but then I simplified it to this:
<?php
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SyncFromJson extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//
$var = "fooooo";
\Log::info("job is running!!!", $var);
}
}
To call the job I created a simple method in a controller that dispatches the job:
$job = (new SyncFromJson())->delay(3);
$this->dispatch($job);
Also tried this:
$this->dispatch(new SyncFromJson());

For what it's worth, I was having a similar problem and implementing 'SelfHandling' seems to have fixed the issue.
Try changing this:
class SyncFromJson extends Job implements ShouldQueue
To this:
class SyncFromJson extends Job implements ShouldQueue, SelfHandling

I had the exact same problem. In my case it turned out it was the incorrect provider in app config that was the problem. I used a previous project as a framework for my new project and inherited the Laravel collective bus package (That was not required.) The moment I removed the collective bus package ( laravelcollective/bus ) , ran composer update and replaced
Collective\Bus\BusServiceProvider::class,
with
Illuminate\Bus\BusServiceProvider::class,
everything worked fine. This may be a similar issue?

Related

Laravel 8 Tests: PHPUnit error: Unknown formatter "unique"

I have written a test that involves a factory. When I execute the test, I get this error:
The data provider specified for Tests\Unit\ExampleTest::testTakePlace is invalid. InvalidArgumentException: Unknown formatter "unique" /var/www/html/api/vendor/fakerphp/faker/src/Faker/Generator.php:249
Expected result
This error should not be shown, I should be able to use $this->faker->unique().
How I tried to fix this problem
By reading the doc again and again (no difference was found) and by reading questions&answers on the Internet (only one question & only one answer were found: to extend Laravel's TestCase but the official documentation, as I mentionned it, says the contrary). (Laravel's TestCase is provided by use Illuminate\Foundation\Testing\TestCase;)
Question
Why doesn't it work and how to fix this bug?
Sources
Test sources
It extends PHPUnit\Framework\TestCase (not Laravel's TestCase) because the documentation says to extend it. Indeed: https://laravel.com/docs/8.x/testing#creating-and-running-tests . This is not the only part of the doc mentionning to extend it.
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Models\Project;
class ExampleTest extends TestCase
{
/**
* #dataProvider provideTakePlaceData
*/
public function testTakePlace($project)
{
$response = $this->json('GET', '/controllerUserProject_takePlace', [
'project_id' => $project->id
]);
}
public function provideTakePlaceData() {
return [
Project::factory()->make()
];
}
}
Controller
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class ControllerUserProject extends Controller
{
public function takePlace(Request $request, $project_id)
{
return;
}
}
The most important: the factory
<?php
namespace Database\Factories;
use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ProjectFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Project::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'id' => $this->faker->unique()->numberBetween(1, 9000),
];
}
}
Change:
use PHPUnit\Framework\TestCase;
to:
use Tests\TestCase;
Why?
When your ExampleTest extends PHPUnit\Framework\TestCase Laravel app is never initialized in tests, and so you don't have access to Laravel features like factories.
The documentation tells you to extend PHPUnit\Framework\TestCase;, but it refers to Unit tests. Feature tests should extend Tests\TestCase. This is something pretty new. Until Laravel 5.8 both unit and feature tests were extending Tests\TestCase by default. I personally just define all tests as feature tests to avoid such issues.
The problem was due to the use of a dataProvider with the use of the factories. More precisely: PHPUnit data providers should not be used when Laravel factories are.
If you are using faker in Factories please make sure these are working correctly regardless (as per example try running Project::factory()->make(); within Laravel Tinker and see the results)
Second common issue (as mentioned above) is the class that you extend your Test with - see above
Third and frequently omitted one that's causing this error, is a missing parent constructor call in the setUp() - (if you use it)
<?php
namespace Tests\Unit;
use Tests\TestCase;
use App\Models\Project;
class ExampleTest extends TestCase
{
protected Project $project;
public function setUp(): void
{
parent::setUp();
$this->project = Project::factory()->make();
}
I think you need to use the WithFaker trait to use faker :
<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Models\Project;
use Illuminate\Foundation\Testing\WithFaker;
class ExampleTest extends TestCase
{
use WithFaker;
// ...
}

Passing parameters to Laravel job is not working

I've read solutions to this problem before but it seems that I'm doing something else wrong and that's why I'm asking: Usually the solution is adding the parameters to the body of the class as well as the __construct method but even doing that it doesn't work.
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Mail;
use App\Mail\TasksFinished;
class SendMailFinished implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public $tries = 3;
protected $msg;
protected $subj;
protected $mailto;
public function __construct($msg, $subj, $mailto)
{
//
$this->msg = $msg;
$this->subj = $subj;
$this->mailto = $mailto;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//Envia correo cuando termine cola.
Mail::to($this->mailto)->queue(new TasksFinished($this->msg, $this->subj));
}
I try to run this through a queue this way in tinker:
use App\Jobs\SendMailFinished;
$job = new SendMailFinished('Hola', 'Prueba', 'ffuentes#example.org');
$job->dispatch();
TypeError: Too few arguments to function
App/Jobs/SendMailFinished::__construct(), 0 passed in
C:/laragon/www/reportes/vendor/laravel/framework/src/Illuminate/Foundation/Bus/Dispatchable.php
on line 16 and exactly 3 expected
Why even after specifying all the parameters both in the class and during instantiation it still cannot see any parameters when dispatching. (I've tried making params public as well but it's the same thing).
When you call dispatch() you should send the parameter there.
Try calling it statically
SendMailFinished::dispatch('Hola', 'Prueba', 'ffuentes#example.org');
There are 2 ways to pass parameters to a dispatching job in laravel.
First is simply call dispatch or dispatchNow as per requirement on your Job class like calling a static method on class:
YourJob::dispatch(argument1, argument2, argument3);
Second is simply pass arguments while creating an instance/object of Job class then pass object to dispatch method(always available in controller) like:
$this->dispatch(new YourJob(argument1, argument2, argument3));
The arguments will be available in the constructor, can you assign them to class local variable properties and use anywhere in Job class.

Laravel: How can a queued job move itself to failed_jobs on fail?

I have a queueable Job that creates a new user...
<?php
namespace App\Jobs;
...
class CreateNewUser implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/** #var array */
public $newUserData;
public function __construct($newUserData)
{
$this->newUserData = $newUserData;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = $this->newUserData['email'];
if (User::whereEmail($email)->count()) {
// TODO: Make this job fail immediately
throw new UserWithEmailExistsException('User with email ' . $email . ' already exists');
}
...
}
}
It's a queued job because we batch process CSVs to load in many users at a time, each one requiring an entry in 2 tables plus multiple entries in roles and permissions tables. Too slow to do synchronously.
I have a check at the start of the handle() method to see if a user with the same email address has not already been created (because potentially several jobs could be queued to create users with the same email) and it throws a custom Exception if it does.
If that check fails, I don't ever want the queue worker to attempt this job again because I know it will continue to fail indefinitely, it's a waste of time to re-attempt even once more. How can I manually force this job to fail once and for all and move over to the failed jobs table?
P.S. I have found the SO answer about the fail() helper and the $this->markAsFailed() method but these still do not immediately move the job from jobs to failed_jobs.
I've completely rewritten my answer for you. I was in a rush last night and thought I had a quick solution to your problem, sorry for the misinformation.
You could do something like the code below, this won't put the job into the failed jobs table but it will prevent the re-attempts from happening. I hope that helps.
<?php
namespace App\Jobs;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class TestJob extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public function __construct()
{
parent::__construct();
}
public function handle()
{
if ($this->attempts() > 0) {
// Will not reattempt this job.
return;
}
throw new \Exception('Job will fail.');
}
}

Laravel 5.5 Queue Dispatch Not Working

Maybe I'm not understanding on Laravel queue works, or maybe it itself is not working, my expected behaviour for Laravel Queue/Dispatch is that if a dispatch is initiated from the Controller, the code dispatched to queue should be executed silently and in the background. The end-user browser should not have to wait for the code to execute.
This is however what happens with my code, the dispatched code to queue leaves the browsers "Spinning..." whilst is executes.
Is this expected behavior? The code:
**Controller:**
public function make_eps_certs($tbl_eps)
{
//dd(Carbon::now()->addMinutes(10))
Log::info('Dispatching maeEPSCert to Queue');
$var_result=makeEPSCerts::dispatch($tbl_eps)->onQueue('eventadmin')
->delay(10);
return redirect()->back();
}
**Job:**
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\partSubs;
use Log;
use Image;
class makeEPSCerts implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
protected $passdata;
public $timeout = 120;
public function __construct($passdata)
{
Log::info('Constructing makeEPSCert');
$this->passdata = $passdata;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
try
{
Log::info('Beginning makeEPSCert');
$tbl_eps=$this->passdata;
.....
Change your LOG_DRIVERin your .env to database and create the needed migration files with php artisan queue:table, after that do a php artisan migrate.
After that you just need to run php artisan queue:work --queue="eventadmin"
and then you will recognize the expected behavior
A more detailed documentation can be found here: https://laravel.com/docs/5.5/queues
You can try again in the following way (I assume that you did instructions in Laravel docs but someday it's not working):
Step 1: drop table 'jobs' in your database.
Step 2: run command 'php artisan migrate' in console to create table 'jobs' again.
Step 3: run command 'php artisan queue:work' in console
Step 4: retry your app
Note that in .env file, you set up:
QUEUE_CONNECTION=database
QUEUE_DRIVER=database
P/s: It works for me!

Laravel mail Invalid view

I have a command in my code that is run daily by cron that sends emails to all new users. It used to work ok, but after I have swithched the queue driver to SQS and upgraded Laravel 5.2 to 5.3 it started throwing an error.
InvalidArgumentExceptionvendor/laravel/framework/src/Illuminate/Mail/Mailer.php:379
Invalid view.
I don't know what might cause the error, because I have not deleted the view. Also when I run the command manually it does not throw any errors.
Here is the command code:
public function handle()
{
$subscriptions = Purchase::where('created_at', '>=', Carbon::now()->subDay())
->groupBy('user_id')
->get();
$bar = $this->output->createProgressBar(count($subscriptions));
foreach ($subscriptions as $subscription) {
$user = $subscription->user;
// if ($user->is_active_customer) {
Mail::to($user)->bcc(env('BCC_RECEIPTS_EMAIL'))->send(new NeedHelp());
// }
$bar->advance();
}
$bar->finish();
$this->info("\nSuccess! " . number_format(count($subscriptions)) . ' emails were sent.');
}
Here is the NeedHelp class code (I have changed the email and sender name for this thread):
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class NeedHelp extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
*/
public function __construct(){
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Need help?')
->from('default#mail.com', 'Sender')
->view('emails.need-help');
}
}
I have found the error. The reason was that I have accidentally connected two applications to the same queue, which caused them to process jobs and emails of each other which resulted in this error.

Resources