Fractal Techware

Alert runbooks /

PostgresqlLongRunningTransaction

A transaction in PostgreSQL has been open for a long time, either still working or sitting idle while holding locks and old snapshots.

   
Severity warning
Source prometheus-community/postgres_exporter 0.15+
Key metric pg_stat_activity_max_tx_duration (labels datname, state)

What it means

The exporter reports the age of the oldest open transaction per database and state. The alert fires when a transaction that is active or idle in transaction has been open for a long time (tens of minutes) and stays that way.

Long transactions hurt in ways that are not obvious: they hold row and table locks that block other writers and DDL, and their snapshot prevents VACUUM from removing dead rows anywhere in the cluster, so tables and indexes bloat while it stays open.

Common causes

First checks

  1. List the oldest transactions:
    SELECT pid, usename, application_name, client_addr, state,
           now() - xact_start AS xact_age, now() - state_change AS in_state_for,
           wait_event_type, left(query, 100) AS last_query
    FROM pg_stat_activity
    WHERE xact_start IS NOT NULL
    ORDER BY xact_start
    LIMIT 10;
    
  2. Check whether it is blocking anyone:
    SELECT pid, pg_blocking_pids(pid) AS blocked_by, left(query, 80)
    FROM pg_stat_activity
    WHERE cardinality(pg_blocking_pids(pid)) > 0;
    
  3. See how long it has been growing:
    max by (instance, datname, state) (pg_stat_activity_max_tx_duration)
    
  4. Also check forgotten prepared transactions, which do not appear as sessions:
    SELECT gid, prepared, owner, database FROM pg_prepared_xacts ORDER BY prepared;
    

Fixing it

Ask the owner if it is a legitimate job. If it is abandoned or blocking production, cancel the query with SELECT pg_cancel_backend(<pid>); or end the session with SELECT pg_terminate_backend(<pid>);. Prevent repeats with idle_in_transaction_session_timeout, per-role statement_timeout for ad-hoc users, and by running reports on a replica.