Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Scheduler/Lock] Lock (flock) do not work when using scheduler with cron #60357

Open
@secit-pl

Description

@secit-pl

Symfony version(s) affected

7.x.x

Description

If we use the Symfony scheduler to generate cyclic messages and we run the scheduler within CRON, the lock (flock) mechanism will not work

How to reproduce

Use default flock lock component DSN in .env

LOCK_DSN=flock

Create message:

<?php

namespace App\Message;

final readonly class EmailTestMessage
{
}

Create message handler

<?php

namespace App\MessageHandler;

use App\Message\EmailTestMessage;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Mime\Email;

#[AsMessageHandler]
final readonly class EmailTestMessageHandler
{
    public function __construct(
        private MailerInterface $mailer,
    ) {
    }

    public function __invoke(EmailTestMessage $message)
    {
        $this->mailer->send(
            (new Email())
                ->to('[email protected]')
                ->subject(sprintf('[EmailTest] %s (pid: %d)', (new \DateTime())->format('H:i:s'), getmypid()))
                ->text('')
        );
    }
}

create scheduler

<?php

namespace App\Scheduler;

use App\Message\EmailTestMessage;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\RecurringMessage;
use Symfony\Component\Scheduler\Schedule;
use Symfony\Component\Scheduler\ScheduleProviderInterface;

#[AsSchedule('default')]
final readonly class DefaultScheduleProvider implements ScheduleProviderInterface
{
    public function __construct(
        private LockFactory $lockFactory,
    ) {
    }

    public function getSchedule(): Schedule
    {
        $from = new \DateTimeImmutable('00:00:00', new \DateTimeZone('UTC'));

        return (new Schedule())->add(
                RecurringMessage::every('30 seconds', new EmailTestMessage(), $from),
            )
            ->lock($this->lockFactory->createLock('default-scheduler'))
        ;
    }
}

Now run 2 schedulers in the same time:

1> symfony console messenger:consume async failed scheduler_default --time-limit=120
2> symfony console messenger:consume async failed scheduler_default --time-limit=120

The lock will work, and you'll get one mail per 30 seconds.

Now configure cron as follows:

* * * * *       ...      php /patch/to/bin/console messenger:consume async failed scheduler_default --time-limit=120 --quiet

This should run 2 concurrent consumers after one minute. When the second scheduler will start you'll start receiving doubled emails every 30 seconds:

Image

Possible Solution

The problem is related to the way how the default configuration of the flock is working if the code is executed by cron. If I change the LOCK_DSN in .env to:

LOCK_DSN=flock://var/lock

the problem will disappear and from now in all cases the scheduler will produce only one message and in the result I'll get only one email.

Image

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions