From a1e3939b7934ff617fff464f4bc85c056d647370 Mon Sep 17 00:00:00 2001 From: philipp Date: Sun, 14 Jun 2026 21:00:28 +0200 Subject: [PATCH] Tolerate concurrent stats index creation Proof: observed the deployed stats fix restart app pods once when concurrent startup index creation hit PostgreSQL pg_class_relname_nsp_index; added an idempotent schema-index helper that treats concurrent already-created index errors as success and added regression tests for the exact duplicate-index race and unrelated duplicate errors. Revalidated targeted stats/schema tests, full npm test, and operator dashboard bundle build. Assumptions: PostgreSQL error 23505 on pg_class_relname_nsp_index and 42P07 during CREATE INDEX IF NOT EXISTS mean another repo-owned process created the same schema object concurrently, so continuing is equivalent to the intended idempotent schema state. Still fake: this does not remove already-written duplicate statistic rows with malformed historical stat_id strings; the loader de-dupes them at read time, and venue-native settlement truth remains limited to existing durable evidence. --- src/lib/postgres.mjs | 21 ++++++++++-- ...stgres-quote-lifecycle-statistics.test.mjs | 33 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/lib/postgres.mjs b/src/lib/postgres.mjs index c78a078..403bb71 100644 --- a/src/lib/postgres.mjs +++ b/src/lib/postgres.mjs @@ -440,7 +440,7 @@ export async function ensureQuoteLifecycleRetentionSchema(pool) { CREATE INDEX IF NOT EXISTS ${QUOTE_LIFECYCLE_STATISTIC_SUBJECTS_TABLE}_bucket_idx ON ${QUOTE_LIFECYCLE_STATISTIC_SUBJECTS_TABLE} (bucket, latest_stage_at DESC NULLS LAST) `); - await pool.query(` + await ensureSchemaIndex(pool, ` CREATE INDEX IF NOT EXISTS ${QUOTE_LIFECYCLE_STATISTIC_SUBJECTS_TABLE}_updated_idx ON ${QUOTE_LIFECYCLE_STATISTIC_SUBJECTS_TABLE} (updated_at DESC) `); @@ -6418,8 +6418,25 @@ function withDepositCreatedAt(payload, effectiveAt) { } async function ensureExpressionIndex(pool, { name, table, expression }) { - await pool.query(` + await ensureSchemaIndex(pool, ` CREATE INDEX IF NOT EXISTS ${name} ON ${table} (${expression}) `); } + +export async function ensureSchemaIndex(pool, sql) { + try { + await pool.query(sql); + } catch (error) { + if (isConcurrentSchemaIndexExistsError(error)) return; + throw error; + } +} + +function isConcurrentSchemaIndexExistsError(error) { + return error?.code === '42P07' + || ( + error?.code === '23505' + && error?.constraint === 'pg_class_relname_nsp_index' + ); +} diff --git a/test/postgres-quote-lifecycle-statistics.test.mjs b/test/postgres-quote-lifecycle-statistics.test.mjs index ff0e799..e5d46f4 100644 --- a/test/postgres-quote-lifecycle-statistics.test.mjs +++ b/test/postgres-quote-lifecycle-statistics.test.mjs @@ -5,6 +5,7 @@ import { buildQuoteLifecycleStatistics, } from '../src/core/quote-lifecycle-statistics.mjs'; import { + ensureSchemaIndex, loadQuoteLifecycleStatistics, refreshQuoteLifecycleStatistics, } from '../src/lib/postgres.mjs'; @@ -192,3 +193,35 @@ test('postgres quote lifecycle statistics loader returns all-time and clamped gr assert.match(issuedSql, /PARTITION BY grain, window_start, window_end/); assert.match(issuedSql, /duplicate_rank = 1/); }); + +test('postgres schema index creation tolerates concurrent already-created index race', async () => { + let queryCount = 0; + const pool = { + async query() { + queryCount += 1; + const error = new Error('duplicate key value violates unique constraint "pg_class_relname_nsp_index"'); + error.code = '23505'; + error.constraint = 'pg_class_relname_nsp_index'; + throw error; + }, + }; + + await ensureSchemaIndex(pool, 'CREATE INDEX IF NOT EXISTS quote_lifecycle_stat_subjects_updated_idx ON quote_lifecycle_stat_subjects (updated_at DESC)'); + assert.equal(queryCount, 1); +}); + +test('postgres schema index creation still rejects unrelated duplicate errors', async () => { + const pool = { + async query() { + const error = new Error('duplicate key value violates unrelated constraint'); + error.code = '23505'; + error.constraint = 'other_unique_constraint'; + throw error; + }, + }; + + await assert.rejects( + () => ensureSchemaIndex(pool, 'CREATE INDEX IF NOT EXISTS unrelated_idx ON some_table (id)'), + /unrelated constraint/, + ); +});