PostgreSQL errors: duplicate key value violates unique constraint (key_value____pkey and semaphore____pkey)

Created on 3 November 2022, over 2 years ago
Updated 11 April 2023, almost 2 years ago

Problem/Motivation

I am seeing a lot of these errors in PostgreSQL logs - generally when running update.php, but also at other times (I haven't nailed down exactly what triggers it, but seems to be related to theme caching):

message: duplicate key value violates unique constraint "semaphore____pkey"
detail: Key (name)=(library_info:gin:Drupal\Core\Cache\CacheCollector) already exists
query: INSERT INTO "semaphore" ("name", "value", "expire") VALUES ('library_info:gin:Drupal\Core\Cache\CacheCollector', '682342772636186141f2d65.49789030', '1667335733.4565')

and:

message: duplicate key value violates unique constraint "key_value____pkey"
detail: Key (collection, name)=(state, system.theme.files) already exists.
query: INSERT INTO "key_value" ("name", "collection", "value") VALUES ('system.theme.files', 'state', '...')

I am not sure if this is specific to Gin, or if this is an upstream issue with Drupal core and PostgreSQL more generally. I will start this issue here, but move it to core if I can reproduce it with another theme (eg: Claro).

I did find two similar issues filed against Drupal 7 core. They may provide some clues, but they appear to be different in their origin:

Steps to reproduce

TBD

Proposed resolution

TBD

Remaining tasks

TBD

User interface changes

None.

API changes

None.

Data model changes

None.

πŸ› Bug report
Status

Active

Version

7.0 ⚰️

Component
PostgreSQL driverΒ  β†’

Last updated 22 days ago

No maintainer
Created by

πŸ‡ΊπŸ‡ΈUnited States m.stenta

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡³πŸ‡±Netherlands daffie

    I think this is a Drupal 7 problem, not Drupal 10.

  • πŸ‡ΊπŸ‡ΈUnited States m.stenta

    @daffie No, I still get these errors consistently on Drupal 9. I've just set up my error log monitoring to ignore them, but it would be nice if I didn't have to do that.

  • πŸ‡³πŸ‡±Netherlands daffie

    @m.stenta: Could you add a test or an other way to reproduce the bug? It is now a bit difficult to solve.

  • Status changed to Postponed: needs info almost 2 years ago
  • πŸ‡³πŸ‡±Netherlands daffie
  • πŸ‡ΊπŸ‡ΈUnited States m.stenta

    I haven't figured out what causes it, and haven't been able to intentionally reproduce it. I host a large number of sites running D9 on PostgreSQL though and my logs show that it is happening pretty consistently. It seems to be correlated to cache rebuild (and/or some cron runs), but it doesn't happen all the time so it's hard to nail down.

  • πŸ‡³πŸ‡±Netherlands daffie

    @m.stenta: Could you possibly add the full query that is failing. That is including the part "EXCLUDED" and the part after "ON CONFLICT". Maybe too many Drupal merge queries in a short timeframe.

  • πŸ‡ΊπŸ‡ΈUnited States m.stenta

    As far as I know, the query I pasted in the issue summary is the entire query that failed.

    I admit I don't have a good sense for how the semaphore table works, but I'm not sure that upsert() is being used for semaphore table modifications... it looks like only insert() and update() are used. Am I reading that correctly?

    https://git.drupalcode.org/project/drupal/-/blob/bef31d1d77de39e8622678a...

  • πŸ‡ΊπŸ‡ΈUnited States mfb San Francisco

    This same error message happens on a clean install of drupal, aside from the theme name being olivero, claro, etc.

    This is because of how drupal tries to acquire the lock by inserting, and then catching the exception. Postgres by default logs an error for such failed inserts, although you could configure postgres to do less verbose logging.

    Failing to acquire the lock is almost guaranteed even with just a single user, because that one page load can bootstrap drupal multiple times when loading CSS and JS files. Easiest way to reproduce is to clear cache and shift-reload page to force your browser to reload all the CSS and JS files.

  • πŸ‡«πŸ‡·France andypost

    Checked my logs and found that pgsql sometimes hangs and after restart is unable to insert into semaphore

    {"timestamp":"2024-08-28T14:33:18.076Z","user":"drupal","dbname":"db","pid":508,"remote_host":"::1","remote_port":"59604","session_id":"66cf352d.1fc","ps_display":"INSERT","session_start":"2024-08-28T10:42:45.000Z","vxid":"4/88","txid":5172853,"error_severity":"ERROR","state_code":"23505","detail":"Key (name)=(cron) already exists.","statement":"INSERT INTO \"semaphore\" (\"name\", \"value\", \"expire\") VALUES ('cron', '186628320366cf352e108841.46027453', '1724856498.0675')","backend_type":"client backend","query_id":0,"message":"duplicate key value violates unique constraint \"semaphore____pkey\""}
    {"timestamp":"2024-08-28T14:33:18.188Z","user":"drupal","dbname":"db","pid":509,"remote_host":"::1","remote_port":"59614","session_id":"66cf352d.1fd","ps_display":"INSERT","session_start":"2024-08-28T10:42:45.000Z","vxid":"5/273","txid":5172855,"error_severity":"ERROR","state_code":"23505","detail":"Key (name)=(cron) already exists.","statement":"INSERT INTO \"semaphore\" (\"name\", \"value\", \"expire\") VALUES ('cron', '1720247566cf352e2d60e7.70432522', '1724856498.1857')","backend_type":"client backend","query_id":0,"message":"duplicate key value violates unique constraint \"semaphore____pkey\""}
    
  • Status changed to Active about 2 months ago
  • πŸ‡·πŸ‡ΊRussia Chi

    Re #7 Writing a test requires concurrent requests and reading PostgreSQL log. That's not what Drupal testing system is capable of. To reproduce the issue manually you can run simultaneously a couple CLI scripts which acquire a lock with the same ID.
    The root reason of this error is explained well in #14.

  • πŸ‡·πŸ‡ΊRussia Chi

    Possible solution is execution SELECT query before the INSERT in the same transaction. Though it may behave differently depending on configured transaction isolation level.

    We can also consider using some third party lock implementation, for instance symfony/lock.

Production build 0.71.5 2024