I want to create new job which will be called by Amazon SQS and using Laravel Queue to push queues.
Currently, I have one job that works perfectly, but when I create another job as below, it has not been called.
class SimpleJob
{
public function fire($job, $data)
{
DB::table('product_prices')
->insert(array('product_id' => 1557,'price' => 100));
$this->success();
}
private function success()
{
$this->job->delete();
}
private function fail($messages = array())
{
Log::error('Job processing fail', $messages);
$this->job->delete();
}
}
I did read this doc but still cannot figure it out.
I am sure that SQS really sent a message since the old job can still be called.
Apart from creating job class and put everything in fire(), what else I need to do when creating new jobs?
This is Laravel 4.2.
Related
when I create a job and before start it , I need run a function ,
i update the class DatabaseJob
<?php
namespace App\Queue\Jobs;
use App\Models\Tenancy;
use App\Http\DatabaseHelper;
use App\Http\Helper;
class DatabaseJob extends \Illuminate\Queue\Jobs\DatabaseJob
{
public function fire()
{
Helper::createJobLog($this->job->id);
parent::fire();
}
}
but it seems the function createJobLog is fired only when the Job start ,I need it when the job created not started .
In a service provider you can listen for the Illuminate\Queue\Events\JobQueued event. Something similar to:
Event::listen(JobQueued::class, function ($event) {
// Of course, if you need to log only the database jobs then you can check the job type
if (!$event->job instanceOf DatabaseJob) {
return;
}
Helper::createJobLog($event->job->getJobId());
});
You may call the function createJobLog() when the job is dispatched. Jobs can be set with a timestamp to delay its start time, if you don’t want the job started immediately after it is being dispatched.
I need to save the request into the database after that i have to call an API to sync the data to the other server.
i do the API call using the finally but it seems PHP still processing it, even when i am sending the response in the try clause.
how do i make this asynchronous ? i want to send the response as fast as possible but still processing the API call after the response.
so this what the simple code look like, describing what i am currently doing.
Code with finally =>
public function store(Request $request)
{
try {
//returning the code early
return response("i am speed", 202);
} catch (\Throwable $th) {
return response($th->getMessage(), 500);
} finally {
//lets says this is the super long too run
$i = 0;
$last = 11111111;
while ($i <= $last) {
$i++;
}
}
}
//this code finish in 1000ms
code without finally =>
public function store(Request $request)
{
try {
return response("i am speed", 202);
} catch (\Throwable $th) {
return response($th->getMessage(), 500);
}
} //this code finish in 90ms;
why this is happen ?
i already sending the response but why it not returning early ?
what can i do to send the response first then continue the execution ?
I already finish this problem.
As the comment suggest Laravel have a feature called a queue that will dispatch the job the database, this process won't running until you run the queue worker.
To make queue what i do is :
First change the .env QUEUE_CONNECTION to database.
QUEUE_CONNECTION=database
Then run this artisan command to setup the queue worker.
php artisan queue:table
php artisan migrate
After that make a job for the function that want to run in the queue.
For example i am gonna put the finally code (the one in the question) in the new job.
php artisan make:job exampleJobName
Then go to exampleJobName.php, write the code that will be running in the queue in the handle function.
public function handle()
{
//lets says this is the super long too run code
$i = 0;
$last = $this->data; //variable from constructor
while ($i <= $last) {
$i++;
}
}
//exampleJobName.php
If a variable need to be pass to the handle, then add a contructor in the __construct function.
public function __construct($data)
{
$this->data = $data;
}
//still inside the exampleJobName.php
Then everything is setup go to the controller that want to run this job (i am gonna take example from question) and change the code to this.
public function store(Request $request)
{
try {
$data = 111111111;
exampleJobName::dispatch($data);
//this will insert the job on the jobs table in the database
//therefore the job won't run until the queue worker is running
return response("i am speed", 202);
} catch (\Throwable $th) {
return response($th->getMessage(), 500);
}
}
//this code finish fast
Everything is ready then just run the queue worker in the terminal side by side with artisan serve.
php artisan queue:work
The queue worker will check to the jobs table if there are any job that hasn't run yet. then will run it one by one.
That's what i do, hope this can help someone.
credit to Tim Lewis in the comment for show me this this link.
Call an API to sync the data to the other server potentially can take a long time so I suggest that you create and dispatch a job for that.
If you still want to do so right after the response is sent, you might want to use dispatchAfterResponse.
I'm using Lumen (Laravel) to handle an AWS SQS queue with the sqs-plain driver for the connection. That driver works the same way as the default sqs driver but allows me to use custom JSON in the queue message body.
Based on that package I've created a job handler that works fine, but I'm having trouble understanding how to properly release a message back to the queue.
In the handler method I've injected a SqsJob and tried calling the release method which isn't working as I'd expect.
It seems that the method SqsJob::release calls changeMessageVisibility on the SQS API and the parent release method, which simply sets a class variable $this->released = true; on the job.
So the "releasing" of the message isn't really done, as much as the message is just being marked as released and the visibility of the message in the queue is changed. Not handling the release would result in the message being "handled" and deleted from the queue.
By trial and error I found out, that throwing an exception in the handler method sends the message back to the queue.
Here's a simplified version of the job handler:
namespace App\Jobs;
use Illuminate\Contracts\Queue\Job as LaravelJob;
use Illuminate\Queue\Jobs\SqsJob;
use Illuminate\Support\Facades\Log;
class HandlerJob extends Job
{
protected $data;
/**
* #param SqsJob $job
* #param array $data
*/
public function handle(SqsJob $job, array $data)
{
if ($this->validData($data)) {
// handle the job
} else {
$this->release(60);
// actually release the job back to queue
throw new \Exception('Invalid Data');
}
}
private function validData($data)
{
//not relevant
}
}
This seems like a basic task to be handled by the queue worker but I can't figure it out.
What is the proper way of releasing a message back into the the queue using the Laravel/Lumen framework?
Below is what's happening when i run php artisan queue:listen and at my job table only have one job
and this is my code :
public function handle(Xero $xero)
{
$this->getAndCreateXeroSnapshotID();
$this->importInvoices($xero);
$this->importBankTransaction($xero);
$this->importBankStatement($xero);
$this->importBalanceSheet($xero);
$this->importProfitAndLoss($xero);
}
In order for a job to leave the queue, it must reach the end of the handle function -- without errors and exceptions.
There must be something breaking inside one or more of your functions.
If an exception is thrown while the job is being processed, the job will automatically be released back onto the queue so it may be attempted again. https://laravel.com/docs/5.8/queues
The same behavior can be achieved with
$this->release()
If you can't figure out what is breaking, you can set your job to run only once. If an error is thrown, the job will be considered failed and will be put in the failed jobs queue.
The maximum number of attempts is defined by the --tries switch used
on the queue:work Artisan command. https://laravel.com/docs/5.8/queues
php artisan queue:work --tries=1
If you are using the database queue, (awesome for debugging) run this command to create the failed queue table
php artisan queue:failed
Finally, to find out what is wrong with your code. You can catch and log the error.
public function handle(Xero $xero)
{
try{
$this->getAndCreateXeroSnapshotID();
$this->importInvoices($xero);
$this->importBankTransaction($xero);
$this->importBankStatement($xero);
$this->importBalanceSheet($xero);
$this->importProfitAndLoss($xero);
}catch(\Exception $e){
Log::error($e->getMessage());
}
}
You could also set your error log channel to be slack, bugsnag or whatever. Just be sure to check it. Please don't be offended, it's normal to screw up when dealing with laravel queues. How do you think I got here?
Laravel try to run the job again and again.
php artisan queue:work --tries=3
Upper command will only try to run the jobs 3 times.
Hope this helps
In my case the problem was the payload, I've created the variable private, but it needs to by protected.
class EventJob implements ShouldQueue
{
use InteractsWithQueue, Queueable, SerializesModels;
// payload
protected $command;
// Maximum tries of this event
public $tries = 5;
public function __construct(CommandInterface $command)
{
$this->command = $command;
}
public function handle()
{
$event = I_Event::create([
'event_type_id' => $command->getEventTypeId(),
'sender_url' => $command->getSenderUrl(),
'sender_ip' => $command->getSenderIp()
]);
return $event;
}
}
The solution that worked for me to delete the job after pushing them into the queue.
Consider the e.g.
class SomeController extends Controller{
public function uploadProductCsv(){
//process file here and push the code inot Queue
Queue::push('SomeController#processFile', $someDataArray);
}
public function processFile($job, $data){
//logic to process the data
$job->delete(); //after complete the process delete the job
}
}
Note: This is implemented for laravel 4.2
I would like to push another job onto the queue after my first one has successfully executed. From my ShopController.php I fire:
$this->dispatch(new ItemPurchased($myVariables));
In ItemPurchased.php:
public function handle()
{
// some code that charges a user's credit card
}
How do i fire a subsequent job upon success of ItemPurchased.php?
From the Laravel Documentation, you would do something like this in a ServiceProvider:
{
Queue::after(function (JobProcessed $event) {
// $event->connectionName
// $event->job
// $event->data
});
}
But how do i specify, after ItemPurchase.php was successfuly, then dispatch another job? There is a failed() method for code to run when jobs fail. Is there a success() method that hasn't been mentioned before?
Jobs run offline through the Queue driver. However, once the handle method is called it follows the normal sync code execution.
So simply at the end of handle method just fire the new job:
public function handle()
{
//Some code here
dispatch(new JobClass());
}