The problem

While working on my Laravel projects, I noticed a recurring pattern: using closure middleware to skip certain jobs after they’ve been queued. This approach is particularly useful when dealing with delayed jobs that need to be skipped under specific conditions.

Here’s an example of how I was handling this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class MyJob implements ShouldQueue
{
    use Queueable;

    public function handle(): void
    {
        // Do something
    }

    public function middleware(): array
    {
        return [
            function ($job, $next) {
                if ($someCondition) {
                    $next($job);
                }
            },
        ];
    }
}

While this approach works, I thought it would be better to have a more elegant and reusable solution.

The solution: a new Skip middleware

To simplify skipping jobs, I created a new middleware class called Skip. Here’s the implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Skip
{
    public function __construct(protected bool $skip = false)
    {
    }

    /**
     * Apply the middleware if the given condition is truthy.
     *
     * @param  bool|Closure(): bool  $condition
     */
    public static function when(Closure|bool $condition): self
    {
        return new self(value($condition));
    }

    /**
     * Apply the middleware unless the given condition is truthy.
     *
     * @param  bool|Closure(): bool  $condition
     */
    public static function unless(Closure|bool $condition): self
    {
        return new self(! value($condition));
    }

    /**
     * Handle the job.
     */
    public function handle(mixed $job, callable $next): mixed
    {
        if ($this->skip) {
            return false;
        }

        return $next($job);
    }
}

Using the Skip middleware

Now, the Skip middleware makes it easier to handle conditional job skipping. Here’s how you can use it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

namespace App\Jobs;

use Illuminate\Queue\Middleware\Skip;

class MyJob implements ShouldQueue
{
    use Queueable;

    public function handle(): void
    {
        // Do something
    }

    public function middleware(): array
    {
        return [
            Skip::when($someCondition),

            Skip::unless($someCondition),

            Skip::when(function(): bool {
                if ($someCondition) {
                    return true;
                }
                return false;
            }),
        ];
    }
}

You use Skip::when() to skip the job when the condition is truthy and Skip::unless() to skip the job when the condition is falsy. You can also pass a closure to both methods to define a custom condition.

Submitting the Skip middleware to Laravel

Sometimes, small improvements can have a significant impact. Noticing the potential of this middleware, I decided to submit a pull request to Laravel. I’m happy to share that it was accepted by Taylor Otwell.

You can check out the PR here: #52645.

I hope you find this new middleware useful in your projects! 🫶

Keep shipping! 🚢