I am working on an app that requires fetching data from a third-party server and that server allows max 1 request per seconds.
Now, all request send as job and I am
If you need "throttling" and are not using Redis as your queue driver you can try to use the following code:
public function throttledJobDispatch( $delayInSeconds = 1 )
{
$lastJobDispatched = Cache::get('lastJobDispatched');
if( !$lastJobDispatched ) {
$delay_until = now();
} else {
if ($lastJobDispatched->addSeconds($delayInSeconds) < now()) {
$delay_until = now();
} else {
$delay_until = $lastJobDispatched->addSeconds($delayInSeconds);
}
}
Job::dispatch()->onQueue('YourQueue')->delay($delay_until);
Cache::put('lastJobDispatched', $delay_until, now()->addYears(1) );
}
What this code does is release a job to the queue and set the start time X seconds after the last dispatched job's start time. I successully tested this with database as queue-driver and file as cache driver.
There are two minor problems I have encountered so far:
1) When you use only 1 second as a delay, depending on your queue worker - the queue worker may actually only "wake up" once every couple of seconds. So, if it wakes up every 3 seconds, it will perform 3 jobs at once and then "sleep" 3 seconds again. But on average you will still only perform one job every second.
2) In Laravel 5.7 it is not possible to use Carbon to set the job delay to less than a second because it does not support milli- or microseconds yet. That should be possible with Laravel 5.8 - just use addMilliseconds
instead of addSeconds
.