Skipping Jobs with When and Unless – Laravel

Lets learn how to skip jobs using Skip middleware. Skip middleware support two method as when() and unless().

  1. When()
    • Skip the job when it return true.
    • If return true job will be not executed.
  2. unless()
    • Skip the job when it return false.
    • If return false job will not execute.

Example of using When() and Unless()

Testing use of when() method and unless() in a complete Laravel example.

Task: Create a Laravel application that activate subscription based on user information.
– Use when() method to not to activate subscriptions for active users.
– Use unless() method to activate subscription for active users.
Here you must return true on both methods to archive above goal.

Setup

Setup a fresh Laravel application. Use Laravel documention for help.

Create a job class

Create a sample job class called ActivateSubscription using below artisan command.

php artisan make:job ActivateSubscription

Open created job class and add below code. Modify constructor method to accept user object.

<?php

namespace App\Jobs;

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

class ActivateSubscription implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct(public object $user)
    {}

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info("Completed the Job for {$this->user->name}");
    }

}

Dispatch the Job

Open web.php file and modify.

  1. Create two users with “name” and “active” attributes.
  2. One user with true and other with false on active field.
  3. Dispatch the job twice using both users.
<?php

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

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

    //Active user
    $user1 = new stdClass();
    $user1->name = "Dave";
    $user1->active = true;

    //Not active user
    $user2 = new stdClass();
    $user2->name = "mark";
    $user2->active = false;

    ActivateSubscription::dispatch($user1);
    ActivateSubscription::dispatch($user2);

});

Run Laravel application

php artisan serve

Run a queue worker

php artisan queue:work

Check Laravel Logs. You will see both jobs executed successfully.

[2024-12-22 11:25:24] local.INFO: Received a get request on root route  
[2024-12-22 11:25:25] local.INFO: Completed the Job for Dave  
[2024-12-22 11:25:25] local.INFO: Completed the Job for mark  

Using when() method to skip jobs

Add Skip middleware to the job class. Here we are using a closure inside the when() method pass the true/false condition.

<?php

namespace App\Jobs;

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

class ActivateSubscription implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct(public object $user)
    {}

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info("Completed the Job for {$this->user->name}");
    }

    public function middleware():array
    {
        //Do not run this job if user is active
        //Skip if return true 
        return [
            Skip::when(fn () => $this->user->active)
        ];
    }

}

Make sure to restart the queue worker. Check Logs file. You will see that active users are not executed. Because when() method skip true conditions (active=true)

[2024-12-22 11:29:54] local.INFO: Received a get request on root route  
[2024-12-22 11:29:56] local.INFO: Completed the Job for mark  

Using unless() method to skip jobs

Add Skip middleware to job class and use unless() method to skip jobs that return false. Here jobs of active users are executed and others were skipped.

<?php

namespace App\Jobs;

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

class ActivateSubscription implements ShouldQueue
{
    use Queueable;

    /**
     * Create a new job instance.
     */
    public function __construct(public object $user)
    {}

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info("Completed the Job for {$this->user->name}");
    }


    public function middleware():array
    {
        //Do not run this job only if user is not active
        //skip if return false.
        return [
            Skip::unless(fn () => $this->user->active)
        ];
    }
}

Restart the queue worker and test the result. You will see only the jobs of users with active true are executed.

[2024-12-22 11:33:59] local.INFO: Received a get request on root route  
[2024-12-22 11:33:59] local.INFO: Completed the Job for Dave