send a message, set a value in cache with a key of smsDelay, and an expiry of 10 seconds
Sending a message, is there a cache key of sms delay? if so, defer sending.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Hi,
I have to send few messages to an SMS API after a pause of 10 seconds between them. How can this be done in Laravel? I don't want to use anything like SLEEP in PHP, because it hangs the whole process for X seconds, and I think it will cause issues in execution. Any better way?
Thanks, Saad
send a message, set a value in cache with a key of smsDelay, and an expiry of 10 seconds
Sending a message, is there a cache key of sms delay? if so, defer sending.
You can your SMS via a notification and apply a delay before sending it.
https://laravel.com/docs/12.x/notifications#delaying-notifications
Put your sendings in queued jobs:
foreach ($to_send as $sms) {
dispatch(new SendSmsJob($sms))->delay(10);
}
Don't forget to set up queue worker.
Update: don't do it, it won't work. All queued jobs will be run simultaneously (or, at least, without 10 seconds delay between each other).
why not fix the code instead of saying don't do it?
$now = now();
foreach ($to_send as $sms) {
dispatch(new SendSmsJob($sms))->delay($now->addSeconds(10));
}
It doesn't fix the problem. The problem of this approach, as @snapey mentioned, is that each job gets the same "available_at" timestamp. Therefore only the first job will have 10 seconds delay. Others will be executed immediately after the first one, without delays.
update: I see $now->addSeconds(10) adds 10s, 20s, 30s etc in every iteration; however it is unreliable since we don't know when exactly jobs start running and how long a job runs.
The problem with delayed queued job is that it will never 'pace' jobs. It just processes the job after 10 seconds time. If a bunch of jobs are queued together, each with a 10 seconds delay. they will all be sent together after 10 seconds.
If the API you are connecting to says you can only send one message every 10 seconds then the above is not going to do that.
A combination of cache key expiry and queued jobs is the solution. If the key exists, re queue the job with a couple of seconds delay.
You're right, simple delay for each job won't work.
Instead of manually playing with cache key, job rate limiter can be utilized: https://laravel.com/docs/12.x/queues#rate-limiting
However, the desired behavior can be achieved using chain and setting delay in job body:
class TestJob implements ShouldQueue
{
public function __construct ()
{
$this->delay = 10;
}
public function handle(): void
{
Log::info($this::class . ' dispatched');
}
}
> php artisan tinker
$chain = Bus::chain([])
$chain->append(new App\Jobs\TestJob)
$chain->append(new App\Jobs\TestJob)
$chain->append(new App\Jobs\TestJob)
$chain->append(new App\Jobs\TestJob)
$chain->append(new App\Jobs\TestJob)
$chain->dispatch()
As you can see, jobs run with ~10 seconds delay each:
[2025-09-29 09:35:38] local.INFO: App\Jobs\TestJob dispatched
[2025-09-29 09:35:50] local.INFO: App\Jobs\TestJob dispatched
[2025-09-29 09:36:03] local.INFO: App\Jobs\TestJob dispatched
[2025-09-29 09:36:15] local.INFO: App\Jobs\TestJob dispatched
[2025-09-29 09:36:28] local.INFO: App\Jobs\TestJob dispatched
thats fine if you know multiple messages need to be sent, but what about more dynamic things like signups, where each is its own action?
I've played around with the rate limiting middleware on queues and say you are allowed to call an api 500 times an hour, the queue will happily process 500 jobs in the first 5 seconds then sit blocked for 59 minutes
queue will happily process 500 jobs in the first 5 seconds then sit blocked for 59 minutes
Why is this wrong? If you have more jobs than your API limits you will fall into rate limiting sooner or later; why it should be later, not sooner? Queue worker tries to do it's job the faster the better.
What scenario would be more suitable, in your opinion?
If you seek for more predictable consumption, maybe apply two rate limiters at the same time:
@saadaan Why are you sending someone SMS messages 10 seconds apart in the first place? That sounds… spammy.
Actually I put SMS just to make a simpler use case. I am sending WhatsApp msgs, and while most of the msgs are initiated on the trigger of an incoming WhatsApp msg from the user first, there are some msgs which I have to send with some time gap. Example: User sends a msg asking for some information; I have to send him a text, an audio and then a video, in 3 back to back msgs. In order to make it easy for the user to receive everything in order and be able to read/listen/view it, I have to put a pause of X seconds between these 3 msgs (so that the screen doesn't scroll up while reading). Thats my exact use case.
my suggestion of using an expiring cache key could work well here since you can set the key per recipient, then avoid delaying other messages.
@saadaan Why not just say what you’re doing instead of changing details like that?
Please or to participate in this conversation.