Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.6k
Description
Symfony version(s) affected
7.3
Description
Current implementation of Symfony Lock forPdoStore
/DoctrineDbalStore
will fail on PostgreSQL if:
- Database connection has an open transaction
- An attempt is made to acquire a lock on a key for a 2nd time
The error message will be:
current transaction is aborted, commands ignored until end of transaction block
and will appear on any SQL statement sent to the database after Store fails toINSERT
(
$sql ="INSERT INTO$this->table ($this->idCol,$this->tokenCol,$this->expirationCol) VALUES (:id, :token,{$this->getCurrentTimestampStatement()} +$this->initialTtl)"; |
Normally it would rarely happen and be limited to developer usage of the lock, but now since Symfony Messenger has deduplication feature - which combines Symfony Lock - there is a high likelihood that dispatching messages within a transaction can lead to an unrecoverable error (when deduplication mechanism should trigger a skip).
How to reproduce
Following test case can be used to trigger the error.
/** * @requires extension pdo_pgsql * * @group integration */publicfunctiontestTransactionWithPostgreSQL():void {if (!$host =getenv('POSTGRES_HOST')) {$this->markTestSkipped('Missing POSTGRES_HOST env variable'); }$key =newKey(__METHOD__);$dsn ='pgsql:host='.$host.';user=postgres;password=password';$pdo =new \PDO($dsn);$pdo->beginTransaction();try {$store =newPdoStore($pdo);$store->save($key);$this->assertTrue($store->exists($key));$store->save($key); }finally {$pdo =new \PDO($dsn);$pdo->exec('DROP TABLE IF EXISTS lock_keys'); } }
Possible Solution
I'd be happy to provide a PR with a fix, but would need directions on how to approach this.
Additional Context
I was able to trigger the issue both in tests (since I am using DAMA Doctrine bundle for tests I have database transaction open almost immediately), and in a real application - when dispatching a message that needed deduplication (i.e. should be skipped).