Skip to content

Creating Isolatable Commands in Laravel

Laravel 9.38 introduced the concept of Isolatable commands, console commands which cannot be run if another instance of the command is already running. I finally had the opportunity to test this out this week, and it works great!

Creating the command

You have to be running a cache provider to make use of this feature. The cache is where Laravel stores the lock telling it that the command is running. You can use any of the following cache drivers: memcached, redis, dynamodb, database, file, or array.

Here is a sample command. The only difference between this command and a non-isolatable command is the implements Isolatable added to the class definition.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Contracts\Console\Isolatable;

class IsolatableCommand extends Command implements Isolatable
{
    protected $signature = 'test:isolate';

    protected $description = 'Example isolated command';

    public function handle(): void
    {
        $this->info("Start");

        sleep(10);

        $this->info('End');
    }
}

Executing a command

To run an isolated command, you have to include the --isolated flag.

php artisan test:isolate --isolated

If the command isn’t running in another process, it will run. If the command is already running, you’ll receive an error message:

The [test:isolate] command is already running.

Sample Use Case

There’s a use-case for isolatable commands built into Laravel, the migrate command. You can run php artisan migrate --isolated to make sure your database migrations don’t run more than once if your application has more than one server in a cluster.

Managing Lock Timeouts

By default, the lock is removed from isolatable commands as soon as the command is done executing. If the command is interrupted or fails to finish, the lock will be lifted after 1 hour.

You can change this time by adding a isolationLockExpiresAt function to your command class. This function would change the lock expiration from 1 hour to 5 minutes:

public function isolationLockExpiresAt()
{
    return now()->addMinutes(5);
}
Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.