Description
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('mail@example.com')
->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:

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.

Additional Context
No response