I am running using Laravel with the Beanstalkd queue driver. I have some long running jobs and I am getting an issue where after about 60 seconds or so the job will move from reserved back to ready state. the job is still running and completes without an issue. The problem is that if another job is added it will not be run next, instead the previous job that has moved back to ready will run. if the job completes before another is added it is not an issue though.
here is my code.
queue push:
Queue::push('myApp\Processors\BuildQuick', $job);
job code:
public function fire($job, $data) {
try {
//some code here that calls another class to build an amazon ec2
} catch (\Exception $ex) {
\Logging::joblog($ex->getMessage(), "ERROR");
$job->delete();
return;
}
}
$job->delete();
\Logging::joblog("Job Completed Successfully", "INFO");
}
update:
I have tested this with a sleep timer and it happens at exactly 1 minute every time. I know it is not throwing any exceptions and all my code does is sleep for 2 minutes.
I finally found what was causing this issue!
https://github.com/laravel/framework/issues/3480
this was added in laravel 4.1 I did not knwo this existed. you must change the default ttr in the queue config. Hope this helps others!
Related
This is a follow up on
Laravel - Running Jobs in Sequence
I decided to go with redis rate limit. Code is below
jobClass {
protected $subscription;
public function __construct(Subscription$subscription) {
$this->subscription= $subscription;
}
public function handle() {
Redis::funnel('mailingJob')->limit(1)->then(function () {
// Job logic...
(new Mailer($this->subscription))->send();
}, function () {
// Could not obtain lock...
return $this->release(10);
});
}
}
And the controller code looks like.
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Subscriptions;
class MailController extends Controller
{
public function sendEmail() {
Subscriptions::all()
->each(function($subscription) {
SendMailJob::dispatch($subscription);
});
}
}
Now, when i run the queue, some of them works rest(around 90%) failed with the below error in horizon.
SendMailJob has been attempted too many times or run too long. The job may have
previously timed out.
What am i missing? Please someone guide me to the right direction.
My goal is to run only one job of a type at one time.
[...] has been attempted too many times or run too long is an error that doesn't tell you why the job failed. It means some other exception has caused your job to fail every time it was attempted by the worker, and the worker has tried it the maximum number of times it was allowed to by your configuration. To understand why it's failing, check your laravel.log file for the exception that caused the job to fail.
In your case, since Mailer is contacting an external system it could be that the system you're connecting to is rate limiting you, or they could be having temporary connection problems or other service downtime. Again, there should be more detail in your log files.
The Laravel documentation has a hint about this:
When using rate limiting, the number of attempts your job will need to run successfully can be hard to determine. Therefore, it is useful to combine rate limiting with time based attempts.
The core of the issue is, the job keeps failing until it can achieve a lock and run.
So I imagine that where you are running your queue worker, you are not setting the --tries flag high enough.
Although you could just set a very high --tries, it is not really scalable.
The best solution, as suggested in the documentation, would be to increase the number of tries as well as using time based attempts
You can also increase return $this->release(10); the release time here. That should have the job wait longer before trying to reacquire a lock, so will use up fewer tries!
I tried php artisan queue:work, its runs great, the website no freezing, but how to run programatically via Controller? i run Artisan:call('queue:work') but its freezing (waiting the queue to finish) and end up gateway timeout, but the queue run successfully though.
Any suggestion?
Queues allow you to defer the processing of a time-consuming task, such as sending an email, until a later time.
So executing the queue worker from controller actually negate the purpose of the queues. Explain your exact use case in question to provide more details.
Try this in your controller function
use Symphony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessTimedOutException;
try {
$process = new Process(your artisan command,
null,
your environment,
[],
timeout(ex: 60000),[]);
$process->run();
} catch (ProcessTimedOutException $e) {
// you can show some flash message
// OR
return Response::json(['message' => 'some message'], 'desire response code');
}
In your case, you need to do some font-end hack, run this controller function as ajax and make some loading. And stop the loading after your desire time is pass.
This is not a best approach, you should not run queue process from controller, you should let your server to do this process by using supervisor, etc…
https://laravel.com/docs/5.1/queues#supervisor-configuration
I'm currently using Laravel's Queue to process a job. I need to release this job some point in time but it runs immediately even if I implemented release(). Is this a bug of laravel or did I miss something?
public function handle()
{
$this->release(120);
var_dump('Hello World!!'); ---> This was displayed right after I called the Job
}
Also, QUEUE_DRIVER is set to RabbitMQ
I don't think release is what you want. Release is that is will be put back into the queue after 120 seconds of being worked at.
If you want it to be in the queue for at least 120 seconds you can used delayed dispatching. https://laravel.com/docs/5.4/queues#delayed-dispatching
For reference:
$job = (new MyJob())->delay(Carbon::now()->addMinutes(2));
dispatch($job);
Very new to queues so be gentle. To my understanding, $job->release() is supposed to put the job back on the queue. I currently have the code below but it only runs the job through the queue once. I need to be able to run it through up to 5 times and if it fails again, delete it or something.
Worker:
public function fire($job, $data)
{
if ($job->attempts() < 5) {
\Log::error($job->attempts());
$job->release();
}
}
PUSH!:
Queue::push(
'ClassName',
[
'path' => $path;
]
Trying to do this locally with sync. Tried running queue:listen and queue:work, then running the push code. Only logged 1 entry. Let me know if you need more info.
Turns out $job->release() doesn't work when using the sync driver.
I have a setup where sometimes a job will timeout. The problem is that it keeps hogging the queue and the other jobs won't run.
I want to delete the jobs which timeout 3 times and continue on with the queue. How can I do this? This is specific to laravel 4.2
The $job object has an attempts method that tells you how many times it tried to run:
public function fire($job, $data)
{
// Try to process. If failed:
if ($job->attempts() >= 3)
{
$job->delete();
}
}