Laravel Job fails during execution: method_exists() - php

We are running on Laravel 6 and we have got the following problem. A job we execute, that counts the number of impressions and clics of certain images triggers the following error, due to a high number of calls to the function:
method_exists(): The script tried to execute a method or access a
property of an incomplete object. Please ensure that the class
definition "App\Jobs\RegisterHouseLog" of the object you are trying to
operate on was loaded before unserialize() gets called or provide an
autoloader to load the class definition
We already increased the number of tries so it executes after sometime, so it's not the actual problem, but it sends an error to our error logs (Slack Channel) and causes a lot of "spam".
I was trying to fix the above error but I wasn't able to fix it, so at least I tried to "mute" the notification through an "failed job exception" but still to it fails.
The best would be to resolve the actual problem, the second best would be to mute it.
Anyone could help?
The Job:
<?php
namespace App\Jobs;
use App\HouseLog;
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 Exception;
class RegisterHouseLog implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 20;
public $house_id;
public $user_id;
public $date;
public $type;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($house_id,$user_id,$type, $date)
{
$this->house_id = $house_id;
$this->user_id = $user_id;
$this->type = $type;
$this->date = $date;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$log = new HouseLog();
$log->user_id = $this->user_id;
$log->house_id = $this->house_id;
$log->type = $this->type;
$log->date = $this->date;
$log->save();
}
public function failed(Exception $exception)
{
Log::critical('Failed Register House');
}
}
And the call:
<?php
namespace App\Http\Controllers\api;
use App\HouseLog;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Jobs\RegisterHouseLog;
use Carbon\Carbon;
class HouseLogController extends Controller
{
public function registerLog(Request $request)
{
$date = Carbon::now();
RegisterHouseLog::dispatch($request->house_id, $request->user_id, $request->type, $date);
}
}
Thanks a lot!!

This error is likely due to the job dispatcher not being able to resolve \App\Jobs\RegisterHouseLog when it pulls from the job queue to kick off a job.
Try clearing the class loader cache:
artisan cache:clear
Also try restarting your job dispatcher process.
artisan queue:restart
It may not be the best solution, but you could also fix this by removing implements ShouldQueue from your job class definition; it would make the job kick off right away without going through the queue.

Related

Get Message-ID from Swift Mailer callback function Laravel Error

I have been stuck in this for quite a while now. I am trying to extract messageID of an email through a callback function and store in DB for later use. I simulated the same conditions in a gmail based server and it works. But I don't think the email server has to do with anything. Here is my mailable class where I try to extract the messageID:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use App\EmailLog;
use App\EmailLogDetail;
class GenericSendEmailMailable extends Mailable
{
//use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
private $applicationTemplate;
public $subject;
private $data;
private $emailLogId;
public function __construct(String $applicationTemplate,Array $data,String $subject, $emailLogId)
{
//
$this->applicationTemplate = $applicationTemplate;
$this->data = $data;
$this->subject = $subject;
$this->emailLogId = $emailLogId;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$emailLogId = $this->emailLogId;
$view = $this->applicationTemplate;
$data = $this->data;
$subject = $this->subject;
return $this->subject($subject)
->view($view,$data)
->withSwiftMessage(function ($message) use ($emailLogId){
$emailLog = EmailLog::where('id', $emailLogId)->first();
if(isset($emailLog->email_log_details)){
foreach($emailLog->email_log_details as $emailLogDetail){
$emailLogDetail->message_id = $message->getId();
$emailLogDetail->save();
}
}
});
}
}
Here, the $message->getId(); should be working fine but its not cause when I send mail and check the DB, the message Id is not stored. By the way, the email send operation is dispatched as a job. Any ideas as to why this is not working?
If anybody is interested in the future, this was due to the heavy processing inside the job. I was facing an execution timeout. I did two things, first I did any trivial processing before dispatching the job rather than in the job itself. And finally I increased the timeout by adding
public $timeout = 300;
in the job class. Also, I increased the "retry_after" in the driver I was using to just a bit more than the actual timeout (320 in my case).
The best way to identify the problem for a queue is to observe the worker.log file and determine whether any jobs failed or not. If failed, the reason (or exception) can be caught by creating a failed_jobs table in your database.

phpunit, laravel: Cannot use "parent" when current class scope has no parent

I'm using PHPUnit 6.5.13 and Laravel 5.5 on PHP 7.4. I recently upgraded from PHP 7.2 to 7.4. and it seems like that triggered the error.
In my test I use $this->expectsEvents in order to test that an event is fired. The test class looks a little like this:
namespace Tests\Feature;
use Tests\TestCase;
use App\Events\OrderReSent;
class MyEventTest extends TestCase {
/** #test */
public function authenticated_client_can_resend()
{
$this->expectsEvents(OrderReSent::class); // there is some more code but this is the line that returns the error
}
}
OrderReSent looks like this (I've tried commenting out broadcastOn and remove InteractsWithSockets use, no change in result):
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class OrderReSent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $invoiceId;
public function __construct($invoiceId)
{
$this->invoiceId = $invoiceId;
}
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
The only place I see parent::__construct being called is in Illuminate\Broadcasting\PrivateChannel, which extends Illuminate\Broadcasting\Channel (and it is a child class, so I don't understand why it would throw this error):
namespace Illuminate\Broadcasting;
class PrivateChannel extends Channel
{
/**
* Create a new channel instance.
*
* #param string $name
* #return void
*/
public function __construct($name)
{
parent::__construct('private-'.$name);
}
}
The stacktrace looks like this and makes me believe Mockery is the culprit:
1) Tests\Feature\MyEventTest::authenticated_client_can_resend
ErrorException: Cannot use "parent" when current class scope has no parent
/project-root/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php:16
/project-root/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php:16
/project-root/vendor/mockery/mockery/library/Mockery/Container.php:219
/project-root/vendor/mockery/mockery/library/Mockery.php:89
/project-root/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php:99
/project-root/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php:54
/project-root/tests/Feature/MyEventTest.php:29
I had same issue - it turned out that mockery/mockery was set to version 0.9 in my composer.json. Upgrading mockery/mockery to version 1.3 solved the problem for me.
Related composer.json fragment:
"mockery/mockery": "~1.3.0",
"phpunit/phpunit": "~8.0",
Try setting same versions and run composer update
The likely culprit is due to new syntax requirements for setUp and tearDown.
Source
It can be caused by a missing return type, which is void.
For example, change this:
public function setUp()
{
parent::setUp();
}
public function tearDown()
{
parent::tearDown();
}
to this:
public function setUp() : void
{
parent::setUp();
}
public function tearDown() : void
{
parent::tearDown();
}
Note: I found this question looking for the error message in a unit test, and oddly enough it was related to m::close(), so I'm describing a different problem than the original question, but my answer will be relevant.

Laravel: Cannot access empty property when trying to send an email

I'm trying to send an email using laravel however I keep getting the cannot access empty property error whenever I run my code.
I've done my research on the error and it seems to be usually caused by using a $ before the property name, example $this->$username instead of $this->username. However, that isn't the case in my code.
I can't really tell what's causing it nor do I have great experience in Laravel
Here's my mailable class:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class VerificationMail extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$data2 = ['companyName' => $this->data['name'], 'verificationCode' => $this->data['verificationCode']];
return $this->from('noreply#REMOVED.com')
->$this->view('emails.verification', $data2);
}
}
My view is saved in resources/views/emails/verification.blade.php
I saw also that this error can sometimes be caused by using $message as variable name inside the views, however that isn't the case with me. I tried loading the view with a normal route without any mail sending involved and it loaded normally.
Can anyone spot it? Thanks.
You have error here:
return $this->from('noreply#REMOVED.com')
->$this->view('emails.verification', $data2);
Use following instead: (remove second $this->)
return $this->from('noreply#REMOVED.com')
->view('emails.verification', $data2);

Laravel/Lumen | Failing to dispatch event

This is my first time using events in Laravel/Lumen.
I am actually using Lumen and I am trying to dispatch an instance of Mailable when a new user signs up in order to send an email in the background.
I believe I have set it up right, but I keep getting this error...
Type error: Argument 1 passed to Illuminate\Mail\Mailable::queue() must implement interface Illuminate\Contracts\Queue\Factory, instance of Illuminate\Queue\DatabaseQueue given
I can't actually see within the error message itself where the issue is coming from e.g. there is no line numbers.
However, this is my code...
AuthenticationContoller.php
$this->dispatch(new NewUser($user));
NewUser.php
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Mail\Mailable;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class NewUser extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('test')->to('test#test.com', 'Test')
->from('test#test.com', 'test')->replyTo('test#test.com', 'test')
->subject('Welcome to the blog!');
}
}
I ran into the same issue. It seems like Lumen and Illuminate/Mailer don't work together all that well.
However I found quite an easy fix in a Github thread.
Basically you just have to create a new service provider in your app/Providers directory.
MailServiceprovider.php
<?php
namespace App\Providers;
use Illuminate\Mail\Mailer;
use Illuminate\Mail\MailServiceProvider as BaseProvider;
class MailServiceProvider extends BaseProvider
{
/**
* Register the Illuminate mailer instance.
*
* #return void
*/
protected function registerIlluminateMailer()
{
$this->app->singleton('mailer', function ($app) {
$config = $app->make('config')->get('mail');
// Once we have create the mailer instance, we will set a container instance
// on the mailer. This allows us to resolve mailer classes via containers
// for maximum testability on said classes instead of passing Closures.
$mailer = new Mailer(
$app['view'], $app['swift.mailer'], $app['events']
);
// The trick
$mailer->setQueue($app['queue']);
// Next we will set all of the global addresses on this mailer, which allows
// for easy unification of all "from" addresses as well as easy debugging
// of sent messages since they get be sent into a single email address.
foreach (['from', 'reply_to', 'to'] as $type) {
$this->setGlobalAddress($mailer, $config, $type);
}
return $mailer;
});
$this->app->configure('mail');
$this->app->alias('mailer', \Illuminate\Contracts\Mail\Mailer::class);
}
}
And then you just have to register this service provider in your bootstrap/app.php instead of the default one by adding the following line:
$app->register(\App\Providers\MailServiceProvider::class);

Laravel job marked as failed, exception saying too many attempts but the job was successful?

I am working with laravel v5.3.30 and I have complex job which is doing guzzle requests and importing data into the system. If I multiple workers with multiple tries I am getting double, even triple insertions into my database. This is what the job looks like overview:
<?php
namespace Uppdragshuset\AO\Tenant\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Uppdragshuset\AO\Tenant\Import\ImportHandler;
class ImportPatentCreateCaseJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
protected $number;
protected $import;
protected $workflow_id;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($number, $import, $workflow_id)
{
$this->number = $number;
$this->import = $import;
$this->workflow_id = $workflow_id;
$this->onQueue('import');
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$importHandler = new ImportHandler();
try {
DB::beginTransaction();
$patent = $importHandler->checkIfPatentExists($this->number['number']);
if( ! $patent){
$patent = $importHandler->handlePatentData($this->number);
}
if( ! $importHandler->checkIfCaseExists($patent->id, $this->workflow_id)){
$task_id = $importHandler->prepareWorkflowAndGetTaskId($this->workflow_id);
$importHandler->createCase($this->workflow_id, $task_id, $patent->id);
}
$this->import->update([
'status' => 'COMPLETED'
]);
DB::commit();
} catch (\Exception $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
DB::rollBack();
$this->import->update([
'status' => 'FAILED'
]);
}
$importHandler->markBatchAsCompleted($this->import);
}
}
I am checking if the data already exists and if it does it should not import it again. I have even wrapped the whole code in a try catch statement so even if something fails, it would log it and the job would run fine.
When I tried with a tries=1, 55 jobs were created, out of which 7 failed but my failed-jobs table shows me 30 rows in there.
So I don't understand how jobs are failing even though I am handling the exceptions. Does anyone have any idea?
push job to queue without workers and process this job manualy

Categories