Laravel job pushed to queue event - php

In Laravel documentation there is Queue::before and Queue::after events. What I'm looking for is "job pushed to queue" or "job created" event, something like Queue::pushed. Is that exists or how can I trigger that event?
In this answer I saw JobPushed event but it's from Laravel Horizon. Is there a way without Horizon?
Queue::before(function (JobProcessing $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
Queue::after(function (JobProcessed $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});

you can use your job class cunstructor function as a job created event. a job object constructor is executed when you create a new instance of it. but other functions (for example: handle() and ...) would execute when job is running in queue.
also for something near job pushed to queue you can override the dispatch function of you job class. job objects have an static function dispatch that pushes a new job object into queue.
so your edited job class would be like these:
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class SampleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct()
{
$this->created();
// rest of code
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
}
public static function dispatch($job)
{
SampleJob::dispatch($job);
$job->pushedToQueue();
}
// events
public function created()
{
// event codes
}
public function pushedToQueue()
{
// event codes
}
}

Related

Getting Job Id in a Laravel queue with Database driver

I have a laravel job which I create from a controller and some times i want to delete those jobs as the timings will be rescheduled
It is a notification job which sends notification one hour before a class and if the class is rescheduled i need to delete the jobs and insert new ones
my controller code is as below
$job = (new OnlineClassRemainderJob($remainder_data))->delay($value);
$id = dispatch($job);
array_push($job_ids, $id);
and the Job class is as shown below
<?php
namespace App\Jobs;
use App\Mail\OnlineClassRemainderMail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Mail;
class OnlineClassRemainderJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $details;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($details)
{
$this->details = $details;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Mail::to($this->details['email'])
->send(new OnlineClassRemainderMail($this->details));
}
}
Kindly show light how I can get the Job id so that i can save it in a database and in case of a reschedule i can remove all job ids related to that class and then dispatch new schedules
I can layout the scenario here
I am scheduling classes for example
I have a class on every day from 20th Jan to 25th Jan at 10 AM and I am scheduling a remainder mail sending job which will fire 1 hour before the class
But at certains scenario the Classes will be rescheduled and for that purpose i need to reschedule the remainders or delete and redispatch the jobs
you need to retrun job id from job with this function $this->job->getJobId();
class OnlineClassRemainderJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Mail::to($this->details['email'])
->send(new OnlineClassRemainderMail($this->details));
retrun $this->job->getJobId();
}
}
then
$job = (new OnlineClassRemainderJob($remainder_data))->delay($value);
$id = dispatch($job);
array_push($job_ids, $id);
ref link https://laravel.com/api/8.x/Illuminate/Contracts/Queue/Job.html#method_getJobId
To take the id of a job before executing it, e.g. to dequeue it before executing it.
$log = UpdateLog::create();
UpdateProduct::dispatch($log)->delay(now()->addMinutes(10));
$regex = 'UpdateLog.*?id\\\\";i:'.$log->id.';';
//delete or get job before start
DB::table('jobs')->where('payload','REGEXP',$regex)->delete();
my job example
//...
class UpdateProduct implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* #var UpdateLog
*/
protected $log;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(UpdateLog $log)
{
$this->log = $log;
}
//...
}

I want to run an async call in laravel and then return true. RETURN TRUE doesn't have to wait for async call to complete

Actually, I have created a shopify app and it's uninstall webhook with it. While uninstalling the app, shopify notify me about the uninstall of app so i could do some relevant process. If shopify doesn't get response in 5 seconds then it hit me with other notification which leads to two calls.
In my webhook function i just delete the shop from my database which sometimes take time. Is there anything i can do in laravel so my deletion process run asynchronously. After calling the deletion process which will be async so my next line of code could return "true". My uninstall function is in InstallController.php in given code below.
in App\Jobs. I have created BackgroundJobs.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\DB;
class BackgroundJobs implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $shopId;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($shopId)
{
$this->shopId = $shopId;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
DB::table("shops")
->where("id", $this->shopId)
->delete();
return true;
}
}
And here is a Controller InstallController.php in which "uninstall()" function dispatch queue.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class InstallController extends Controller
{
public function index()
{
return view("install");
}
public function uninstall(Request $request)
{
$shop_id = $request->get('shopId');
// dispatching job
dispatch(new \App\Jobs\BackgroundJobs($shop_id));
return "true";
}
}
So how can i return "true" and doesn't need to wait for queue to finish ?
You can use job events for execute code after or before complete your job
so you define on boot method in AppServiceProvider
public function boot()
{
Queue::before(function (BackgroundJobs $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
Queue::after(function (BackgroundJobs $event) {
// $event->connectionName
// $event->job
// $event->job->payload()
});
}
for more details please check official document
https://laravel.com/docs/5.8/queues#job-events

The failed() method is not being called when an Job fails in Laravel 5.4

Currently im creating a job to be queued but for some reason the failed() method is not being triggered when the code executed in the handle() method of the job throws an exception. Is this some kind of bug in Laravel or am I doing something wrong? the Queue::failing() method in my AppServiceProvider IS being called
<?php
namespace App\Jobs;
use App\Models\Email;
use Carbon\Carbon;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class MyCommand implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
protected $lead;
/**
* Create a new job instance.
*/
public function __construct($lead)
{
$this->lead = $lead;
}
/**
* Execute the job.
*/
public function handle()
{
throw new \Exception("error!");
}
/**
* The job failed to process.
*
* #param \Exception $exception
*/
public function failed(\Exception $exception)
{
\Log::critical('wooot');
}
}
In the above job. The failed() method is never being called. We use supervisor to keep the queue running
Thank
It looks like the failed() method was being called but because of the $lead property not being public. I got an exception when I wanted to retrieve the contents of the property.

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

Categories