Easy locks with Symfony

Easy locks with Symfony

The Symfony documentation describes quite well how locks actually work, that's why this article will not describe why you should use a lock and how it actually works. But it says nothing about the short time installation it requires to set it up and run!

Let's see that together.

Install the lock component with composer just like any other Symfony component:

composer require lock

This component is one of the rare components that will not come with a recipe, you need to add the configuration yourself, and it's quite easy.

# In the file packages/lock.yaml
framework:
    lock: 'redis://localhost'

This is an example to configure a redis, but it could work with your database directly: lock: '%env(DATABASE_URL)%'

Here is a command that uses our lock, it's that simple!

class LockTestCommand extends Command
{
    protected static $defaultName = 'app:lock-test';

    private LockFactory $lockFactory;

    public function __construct(LockFactory $lockFactory)
    {
        $this->lockFactory = $lockFactory;
        parent::__construct();
    }

    protected function configure()
    {
        $this
            ->setDescription('This is a simple lock test')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        $lock = $this->lockFactory->createLock('test-lock');

        while (!$lock->acquire()) {
            $io->comment('Waiting for the lock');
            sleep (1);
        }

        $io->success("Lock acquired");
        $this->task();

        $lock->release();

        return 0;
    }

    private function task()
    {
        sleep(10);
    }
}

The previous configuration only registers the default lock (and its store and factory) that will be automatically injected to your services. But you can actually define many locks (and keeping the default one!). Here is how:

framework:
    lock:
        default: '%env(DATABASE_URL)%'
        redis_high_availability: ['redis://r1.docker', 'redis://r2.docker']

This will generate a lock factory as a service named lock.redis_high_availability.factory, and you will need to specify it explicitely in your services configuration to use it.

I hope it helps! Please let us know in the comments if there's any mistake or a better way to do it.

Show Comments