Description
Symfony version(s) affected
7.2.4
Description
We are using Scheduler in combination with Lock and encountering a minor issue with setting the expiration of locks. We followed the steps outlined in Efficient management with Symfony Scheduler
However, when attempting to refresh our lock, it passes a floating-point number, as shown below.
namespace Symfony\Component\Scheduler\Generator;
final class Checkpoint implements CheckpointInterface
{
public function release(\DateTimeImmutable $now, ?\DateTimeImmutable $nextTime): void
{
// I stripped all the other code
$this->lock->refresh((float) $nextTime->format('U.u') - (float) $now->format('U.u') + $remaining);
}
}
Then the refresh
method calls putOffExpiration
and that's when the error occurs.
How to reproduce
Used config:
- Devenv (Nix) on a aarch64-darwin
- PostgreSQL 16.5
- PHP 8.3.14
- Symfony 7.2.4
- Symfony Messenger
- Symfony Lock with DoctrineDbalStore
LOCK_DSN=postgresql://user:[email protected]:5432/symfony
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\Schedule;
use Symfony\Component\Scheduler\ScheduleProviderInterface;
use Symfony\Contracts\Cache\CacheInterface;
(new Schedule())
->stateful($cache)
->lock($lock->createLock('scheduler', 30));
When enabling the lock part of the Scheduler the following process is triggered:
Inside DoctrineDbalStore
an UPDATE query is composed that reads:
UPDATE $this->table SET $this->expirationCol = {$this->getCurrentTimestampStatement()} + ?, $this->tokenCol = ? WHERE $this->idCol = ? AND ($this->tokenCol = ? OR $this->expirationCol <= {$this->getCurrentTimestampStatement()})
The value of the first ? contains the TTL.
UPDATE lock_keys SET key_expiration = CAST(EXTRACT(epoch FROM NOW()) AS INT) + $1, key_token = $2 WHERE key_id = $3 AND (key_token = $4 OR key_expiration <= CAST(EXTRACT(epoch FROM NOW()) AS INT))
That will result in an error like:
invalid input syntax for type integer: "354.82824206352"
Possible Solution
I see two possible solutions:
- Convert the value to an integer, sacrificing precision.
- Change the field type in the database from integer to numeric.
If either of these solutions is viable, I'm happy to implement the necessary changes myself and contribute them back.