Skip to content

[Lock] [DoctrineDbalStore] Key expiration is casted as integer but is a float #59938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
manuelderuiter opened this issue Mar 7, 2025 · 1 comment

Comments

@manuelderuiter
Copy link
Contributor

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:password@127.0.0.1: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.

Additional Context

Image

@DennisdeBest
Copy link

I am having the same issue, changing the field type for the key_expiration to numeric did not resolve the issue for me.

I am trying to maybe find a way to use a decorator to force the casting to an int but no success so far.

I am using

PostgreSQL 16.6
PHP 8.4.5 FrankenPHP
Symfony 7.2.6
Symfony Messenger
Symfony Lock with DoctrineDbalStore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants