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

Skip to content

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

Open
@manuelderuiter

Description

@manuelderuiter

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.

Additional Context

Image

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