Laravel database queuing jobs attempts - php

I implemented a laravel queue with the database driver, in an Ubuntu 14.04 server. I execute this code
php /path to app/artisan queue:listen --tries=3 --env=local
It says tries=3. But when I see the jobs table I see jobs with 22 attempts, how is this possible? it should try 3 times and then add it to failed_jobs table.
Also, what does reserved_at means in the jobs table?.
Thank you
Here is the job that, by the way, it works perfectly
<?php
namespace App\Jobs;
use App\Jobs\Job;
use App\Notifiers\Im_Notification;
use App\Notifiers\Notification;
use App\Notifiers\Mail_Notification;
use App\Reservation;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class NotifyPlaceReservationStatus extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
protected $notification;
protected $reservation;
protected $info_changed;
public function __construct(Notification $notification,Reservation $reservation)
{
$this->reservation = $reservation;
$this->notification = $notification;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$this->notification->notifyPlaceReservationStatus($this->reservation);
}
public function failed()
{
error_log('Job failed');
}
}

When you provide the number of tries in the CLI, Laravel worker is going to apply the tries limit only for those jobs currently in the queue (or in your unexecuted job table if you prefer). In order to make every execution of a job have a try limit, you should put a public $tries attribute in your Job class as stated in the Laravel documentation on Dispatching Jobs (for Laravel 5.4)
public $tries = 3;
protected $notification;
protected $reservation;
protected $info_changed;

Related

Laravel scheduler run queue

Hello i have a laravel queue for save operations to do later
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 SumoCoders\Teamleader;
use Illuminate\Notifications\Messages\SlackMessage;
use Monolog\Handler\Slack;
use Illuminate\Support\Facades\Mail;
/**
* Class ProcessNotifications
*
* #package App\Jobs
* Worker for send the notifications slack / mail / teamleader in asincr way
*/
class ProcessNotifications implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $arrayDataNotification ;
protected $typeNotification;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($arrayDataNotification , $typeNotification)
{
$this->typeNotification = $typeNotification;
$this->arrayDataNotification = $arrayDataNotification;
\Log::debug('createNotif',$arrayDataNotification);
}
/**
* Execute the job.
*
* #return void
*/
public function handle($arrayDataNotification , $typeNotification)
{
//first get type of notification
\Log::debug('debug handle ',$this);
\Log::info('into handle '.$this->typeNotification);
if($this->typeNotification=='mail'){
//mail internal
}
if ($this->typeNotification=='slack'){
//notifications slack
}
if($this->typeNotification=='teamleader'){
//teamleader connection
}
}
}
For send a a new job to the queue i am using dispatch method :
$this->dispatch(new ProcessNotifications(['data1', 'data2', 'data3'], 'slack'));
I have all in ddbb in the job table , then params are ok
i setted my crontab by run schedule:run each 5 minutes, is launched ok , but on method schedule , when the method handle is called , the params are lost , and i have this in the function scheduler:
protected function schedule(Schedule $schedule)
{
Log::debug('running scheduler '.date("d-m-Y H:i:s"));
$schedule->job(ProcessNotifications::dispatch());
}
Then , the params in this point is lost, same if i run in console php artisan queue work i have :
Too few arguments to function App\Jobs`\ProcessNotifications::__construct()`
in my ddbb i have all params, but i dont know how recover or if this is the good way to call the queue ?
Ok i found, parameters under function handle not need parameters, this is serialized / unserialized automatically for the queue

Laravel job executing multiple times in queue

Hi I have a laravel job as follows:
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 Timeline\Timeline;
class testQueue implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* #return void
*/
public function handle(Timeline $timeline, $tag)
{
$tagData = $timeline->getTagFeed($tag)->getRankedItems();
if ($tagData) {
echo "boom";
}
}
}
I'm running it via a route as follows:
Route::get('/queue', function () {
$timeline= new Timeline();
$timeline->login("test", "testpwd");
Queue::later(5, new testQueue($timeline, "Testtag"));
});
Then on the commandline I ran:
php artisan queue:listen database
However, that one job is running 255 times instead of 1 times and exiting successfully.
What am I doing wrong?
The documentation states:
Binary data, such as raw image contents, should be passed through the
base64_encode function before being passed to a queued job. Otherwise,
the job may not properly serialize to JSON when being placed on the
queue.
So you shouldn't use public function handle(Timeline $timeline, $tag) (or public function handle(Instagram $currentInstagram, $tag) in your conversation, as the Timeline or something is binary data.
Delete the job after execution.

Why BroadCastEvent are queued in Laravel? How to stop that?

I am working on the project which need to broadcast latitude and longitude on realtime
I have something like below
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Support\Facades\Redis;
class TrackersBroadcast extends Event implements ShouldBroadcast
{
public $lat, $lng,$imei,$date_time
use SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(
$lat,
$lng,
$imei,
$date_time
)
{
$this->lat = $lat;
$this->lng = $lng;
$this->imei = $imei;
$this->date_time = $date_time;
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return ['tracker-channel'];
}
}
In some case I need to trigger real time email , so I decided to implement laravel message queue like below
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Mail;
class SendAlertEmail extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public $data;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($data)
{
$this->data=$data;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//
Mail::send('emails.test', ['testVar' => $this->data], function($message) {
$message->from('no-reply#sample.com', 'Website Name');
$message->to('developer#gmail.com')->subject('A simple test');
});
}
}
whenever I run php artisan queue:listen database it will queue my broadcasting event too . I dont want to queue the broadcast event . How to do that?
Because Laravel Event Broadcasting queued by default if you extend ShouldBroadcast interface. If you don't want Event Broadcasting queued, you should extend ShouldBroadcastNow interface.
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class TrackersBroadcast implements ShouldBroadcastNow
{
......
}
So It means your Event Broadcasting will using sync queue driver.
In Laravel all event broadcasting is queued by default.
Before broadcasting events, you will also need to configure and run a queue listener. All event broadcasting is done via queued jobs so that the response time of your application is not seriously affected.
In you case you gonna need two queue drivers. One for event broadcasting with real time support. One for handling emails with queue support. For this you gonna need two queue drivers. You can define them in config/queue.php
In your SendAlertEmail class do this.
public $broadcastQueue = 'queue-name-for-handling-emails';
In your TrackersBroadcast state the real time queue. This is your redis queue driver.
public $broadcastQueue = 'real-time-queue';
Refer Broadcast queue under Defining broadcast events
Then you can listen for your two queues like this
$php artisan queue:listen --queue="queue-name-for-handling-emails"
$php artisan queue:listen --queue="real-time-queue"
Refer Why event broadcast is queued ?
Hope you find this useful.
May be you can mention queue name in broadcast event like this and don't listen that queue incase you don't need to process
//php artisan queue:listen --queue=broadcast-queue
/**
* #return string
*/
public function onQueue()
{
return 'broadcast-queue';
}

Laravel. Common queue for two projects

I have two different projects.
Laravel project A and Laravel project B.
And I need create task from Project A to project B through queue.
And I dont want create Job for this in Project A.
Currently my realisation is:
Project A
Job with state but without business logic:
<?php
namespace App\Jobs;
use ...;
/**
* Fake class!!!
*/
class MyJob extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public $queue = 'MyQueue';
/**
* Some state
*/
protected $_contentId;
public function __construct($contentId)
{
$this->_contentId = $contentId;
}
/**
* Excess. I dont need business logic in project A.
*/
public function handle()
{
}
}
And I push job into queue in Project A:
...
$this->dispatch(
new MyJob($this->_contentId)
);
...
Project B
<?php
namespace App\Jobs;
use ...;
/**
* Really needed class
*/
class MyJob extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public $queue = 'MyQueue';
/**
* Some state
*/
protected $_contentId;
public function __construct($contentId)
{
$this->_contentId = $contentId;
}
/**
* Here is my business logic. In Project B!
*/
public function handle()
{
Artisan::call('my_command', [
'id' => $this->_contentId,
]);
}
}
So, how to do without MyJob in Project A?
if you connect both laravels apps to a same queue server. you can put jobs on the other site queue. For example, if you are in Laravel A
$job = (new Job())->onQueue('theQueueForLaravelB')
dispatch($job);
But to complete this, you should make a basic job that dispach a new one with parameter data. Like:
class DispatchNewJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
private $class_to_create;
private $data;
public function __construct($class_to_create, $data)
{
$this->class_to_create = $class_to_create;
$this->data = $data;
}
public function handle()
{
dispatch(new $this->class_to_create($this->data));
}
}
So, you can now dispatch any job from laravel A, to laravel B with any data.
You can call
$job = (new DispatchNewJob('App\Jobs\JobInLaravelB', ['data'=>'myawesomedata'])
->onQueue('LaravelBQueue');
dispatch($job);
Sorry for my english, i'm from Argentina.
Laravel expects both ends (dispatcher and listener) to run the same application - so that serializations and deserializations work correctly.
Out of box, Laravel (or Lumen) doesn't support plain queue messages so that receiving end may run a different application or framework.
If you use SQS for queues, my custom SQS connector can help you. Otherwise, you would have to write one yourself.
How about this (it's a total hack though), create a composer project that contains a bunch of Job classes and a bunch of job-handler classes, for example:
<?php
namespace Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class JobType1 implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
JobType1Handler::handle();
}
}
class JobType1Handler
{
public static function handle()
{
}
}
and then modify the handler code in your Project B . So you would be modifying the source in your /vendors folder, which would make deployment difficult.
#Kolovious Answer is the correct one, only two notes:
DispatchNewJob should exists on both Laravel A & B
There's a typo, it should be $this->class_to_create and not $this->$class_to_create

Laravel add multiple Jobs at a time

For a user action, I need to send email to all of his subscribers. In this case, the emails should be queued to send later.
I used jobs for that, which can accept single user instance at a time (followed Laravel Doc) and it inserts a job in job table. This is fine.
Now, as the subscribers number is more that one, how can I add multiple user instance or jobs at a time in the jobs table? In Laravel 5.2, how can I achieve that?
I'm not sure if i'm missing something here by reading your question, but if you are implementing your own job queue, couldnt you just change the constructor to accept an collection (array) of users instead and in the handle method simply run a foreach which would email them?
Example in Laravel docs modified to accept a collection of users instead of single user:
<?php
namespace App\Jobs;
use App\User;
use App\Jobs\Job;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendReminderEmail extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $users = [];
/**
* Create a new job instance.
*
* #param User $user
* #return void
*/
public function __construct($users) //Pass in an array of your user objects
{
$this->users = $users;
}
/**
* Execute the job.
*
* #param Mailer $mailer
* #return void
*/
public function handle(Mailer $mailer)
{
foreach($users as $currentUser){
$mailer->send('emails.reminder', ['user' => $currentUser], function ($){
//code here
});
$currentUser->reminders()->create(...);
}
}
}

Categories