DBAtlas · Atlas de operaciones de bases de datos

Aplicar DDL de forma segura con lock_timeout y reintentos (evitar colas de bloqueo)

PostgreSQLSesiones

Comando

-- Single attempt: give up if the lock is not acquired within 3 s instead of queueing and blocking traffic
SET lock_timeout = '3s';
ALTER TABLE customer ADD COLUMN IF NOT EXISTS segment text;
RESET lock_timeout;

-- Automatic retry: up to 5 attempts, 3 s apart
DO $$
DECLARE
  attempt int := 0;
BEGIN
  LOOP
    attempt := attempt + 1;
    BEGIN
      SET LOCAL lock_timeout = '2s';
      ALTER TABLE customer ADD COLUMN IF NOT EXISTS segment text;
      RAISE NOTICE 'OK, attempt %', attempt;
      EXIT;
    EXCEPTION WHEN lock_not_available THEN
      RAISE NOTICE 'lock not acquired, attempt %', attempt;
      IF attempt >= 5 THEN RAISE; END IF;
      PERFORM pg_sleep(3);
    END;
  END LOOP;
END $$;

Qué hace

Evita que un DDL que necesita ACCESS EXCLUSIVE espere indefinidamente cuando no obtiene el bloqueo, y que bloquee todas las consultas que se encolan detrás de él (lock queue); reintenta a intervalos cortos.

Cuándo usarlo

Al aplicar en producción, sobre tablas con mucha actividad, cambios rápidos pero con bloqueos fuertes como ALTER TABLE, CREATE/DROP TRIGGER, ATTACH PARTITION o RENAME.

Precaución

Sin lock_timeout, un ALTER TABLE encolado detrás de un solo SELECT largo también hace esperar a todas las lecturas/escrituras posteriores y puede agotar el connection pool en minutos. lock_timeout solo limita la espera del bloqueo; no limita el tiempo de ejecución de un DDL que reescribe la tabla (p. ej., cambiar el tipo de una columna). El bloque DO es una sola transacción y mantiene un snapshot entre intentos; para escenarios de reintentos largos es preferible un bucle externo en shell.

Abrir en DBAtlas →

Relacionado