Job Dispatching Conditions

Dispatch() of Laravel job can have certain conditions like dispatchIf, dispatchUnless, etc. Lets learn all dispatch options provided by Laravel.

Table of Content

  1. Dispatch
  2. DispatchIf Vs DispatchUnless
  3. Delay
  4. WithoutDelay
  5. DispatchSync

Dispatch

You can directly dispatch your job using dispatch() method.

DispatchIf and DispatchUnless

You can use these two dispatch methods to run your job or based on the condition provided. Using both is like using true and !true condition inside the if statement. If you pass a condition that return true for both dispatchIf and dispatchUnless it behave like true and !true nature.

    //Dispatch only if the condition is true.
    ProcessImage::dispatchIf(condition,  ....arguments);

    ProcessImage::dispatchIf(true, $user); //Execute
    ProcessImage::dispatchIf(false, $user); //Does not execute
    //Dispatch only if the condition is false
    ProcessImage::dispatchUnless(condition, ....arguments);

    ProcessImage::dispatchUnless(true, $user); //Does not execute
    ProcessImage::dispatchUnless(false, $user); //Execute

Delay job dispatch

Here you can delay adding the Laravel job to the queue in order to delay the dispatch process. Use delay() method on the dispatch() method.

//Add this job to queue after 5 minutes delay
ProcessImage::dispatch()->delay(now()->addMinutes(5));

Without Delay method

You can add a delay variable to job classes to delay job being added to queue for processing. If there is a need to execute that job without the default delay you can use withoutDelay() method on dispatch() method.

Laravel Job with a default delay

create a sample job class called ProcessImage using below artisan command.

php artisan make:job ProcessImage

Modify ProcessImage job class.

  1. Here we are using $delay variable in Queueable trait.
  2. Define $delay variable to override default variable in the Queueable trait.
  3. Add your delay value inside the constructor.
<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;

class ProcessImage implements ShouldQueue
{
    use Queueable;

    public $delay;
    
    /**
     * Create a new job instance.
     */
    public function __construct()
    {
        $this->delay = 10;
    }

    /**
     * Execute the job.
     */
    public function handle()
    {
        Log::info("Done Processing Image Processing Job");
    }
}

Now dispatch above created job class. Open web.php.

<?php

use App\Jobs\ProcessImage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    Log::info("Received a get request on root route");
    ProcessImage::dispatch();
});

Run above application

php artisan serve

Run a queue worker

php artisan queue:work

Check logs

[2024-12-24 00:58:44] local.INFO: Received a get request on root route  

# 10 seconds delay before adding job to the queue 

[2024-12-24 00:58:55] local.INFO: Done Processing Image Processing Job  

Overriding default delay of a Laravel job class

We can use withoutDelay() method on the dispatch() method to execute laravel job class overriding any defined delays in the job class.

<?php

use App\Jobs\ProcessImage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    Log::info("Received a get request on root route");
    ProcessImage::dispatch()->withoutDelay();
});

Logs:

Job class immediately added to the queue for processing.

[2024-12-24 01:11:10] local.INFO: Received a get request on root route  
[2024-12-24 01:11:11] local.INFO: Done Processing Image Processing Job  

Dispatch Sync method

Imagine you have a Laravel job that uses queueable interface. You want one instance of that job class to execute on the same http request immediately without moving it to the queue for later processing. You can use dispatchSync method instead of dispatch method.

Example using DispatchSync method

Create a sample Laravel job using below artisan command.

php artisan make:job ProcessImage

Add below code to ProcessImage job class.

  1. Accept string argument when dispatching the job. Constructor $data variable.
  2. Add 10 second sleep to simulate time consuming task.
  3. Log before and after the sleep to track when the job processing start and end.
<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;

class ProcessImage implements ShouldQueue
{
    use Queueable;
    /**
     * Create a new job instance.
     */
    public function __construct(public string $data)
    {       }

    /**
     * Execute the job.
     */
    public function handle()
    {
        Log::info("Processing... $this->data");
        sleep(10);
        Log::info("Done... $this->data");
    }
}

Now use disptach and dispatchSync to process this job. Here we are using web.php file.

  1. Run three instances of the same job.
  2. Use dispatch() on the first 2 instances of the same job to create a queue.
  3. Use dispatchSync() on last job instance to see what happen.
<?php

use App\Jobs\ProcessImage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    Log::info("Received a get request on root route");
    ProcessImage::dispatch('::Dispatch method');
    ProcessImage::dispatch('::Dispatch method');
    ProcessImage::dispatchSync('::Dispatch Sync');
    return "success";
});

Now check Laravel logs. Even though DispatchSync job was called at the end, it start processing and completed the job before all others.

    [2024-12-24 10:43:41] local.INFO: Received a get request on root route  
    [2024-12-24 10:43:41] local.INFO: Processing... ::Dispatch Sync  
    [2024-12-24 10:43:44] local.INFO: Processing... ::Dispatch method  
    [2024-12-24 10:43:51] local.INFO: Done... ::Dispatch Sync  
    [2024-12-24 10:43:54] local.INFO: Done... ::Dispatch method  
    [2024-12-24 10:43:54] local.INFO: Processing... ::Dispatch method  
    [2024-12-24 10:44:04] local.INFO: Done... ::Dispatch method