Laravel. Common queue for two projects - php

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

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;
}
//...
}

Laravel [5.3|5.4] testing dispatch of job within a job

I'm struggling to understand how I could test a dispatch of a job within another job. I'll provide a code sample.
This is my main job class, we can call it father
final class FatherJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*/
public function __construct()
{
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
\Log::info("Hello World, I'm the father.");
dispatch(new ChildJob());
}
}
Then we have the child job
final class ChildJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*/
public function __construct()
{
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
\Log::info("I'm the child");
}
}
The test has been set as following
final class JobTest extends TestCase
{
/** #test */
public function it_has_been_dispatched()
{
$this->expectsJobs(ChildJob::class);
dispatch(New FatherJob ());
}
}
This test fails, of course that's the whole point of the question, but why?
I've done some digging and I presume that the problem relies on the call withoutJobs() inside expectsJobs(), it seems that withoutJobs() distrupt the current queue thus it doesn't allow to call the rest of the jobs but maybe I am totally off track.
If this logic is intended, how can I create a test suite that allows me to check if the job within a job has been called?
Thank you in advance.
expectsJobs mock all jobs engine. You can't use dispacth().
$this->expectsJobs(ChildJob::class);
$job = new FatherJob();
$job->handle();

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.

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.

Laravel database queuing jobs attempts

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;

Categories