Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

saadaan's avatar

Inserting PAUSE in sending messages

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

1 like
14 replies
Snapey's avatar

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.

1 like
Glukinho's avatar

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).

1 like
krisi_gjika's avatar

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));
}
Glukinho's avatar

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.

Snapey's avatar

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.

3 likes
Glukinho's avatar

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
1 like
Snapey's avatar

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

Glukinho's avatar

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:

  1. 500 per hour
  2. 10 per minute
martinbean's avatar

@saadaan Why are you sending someone SMS messages 10 seconds apart in the first place? That sounds… spammy.

1 like
saadaan's avatar

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.

Snapey's avatar

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.

Please or to participate in this conversation.