Schedule icon
Query icon
Script icon
Docker icon
If icon
SlackIncomingWebhook icon
Log icon
Return icon

PostgreSQL Autovacuum Wraparound Risk Sentinel

Monitors PostgreSQL datfrozenxid transaction age to detect autovacuum wraparound risk before database enters emergency read-only mode.

Categories
DataInfrastructure

PostgreSQL employs 32-bit transaction IDs (XIDs), creating a maximum circular sequence limit of approximately 4 billion transactions. To prevent transaction wraparound, where past committed tuples appear to be in the future, PostgreSQL reserves 2 billion transactions for past visibility and continuously freezes older tuples via the autovacuum daemon.

If autovacuum workers are impeded by long-running transactions, lock contention, or heavy write workloads, transaction age (age(datfrozenxid)) continues to climb toward the 2.14 billion freeze horizon. When transaction age crosses the critical threshold (usually 2.0 billion transactions), PostgreSQL shuts down completely, refusing all new insert, update, and DDL commands, and only permits manual VACUUM FREEZE operations in single-user maintenance mode.

This blueprint implements an automated database durability guard that queries pg_database daily, computes transaction age percentages across all active databases, and dispatches high-urgency Slack notifications before critical freeze horizons are reached.

How it works

  1. Scheduled Daily Audit: The daily_wraparound_check trigger (io.kestra.plugin.core.trigger.Schedule) executes daily at 03:00 UTC.
  2. Freeze Horizon Query: The query_database_freeze_horizon task (io.kestra.plugin.jdbc.postgresql.Query) executes SQL against pg_database to calculate age(datfrozenxid) and capacity percentages.
  3. Python Risk Scoring: The analyze_wraparound_risk task (io.kestra.plugin.scripts.python.Script) checks databases against freeze_max_age_warning_threshold (default: 1.5 billion transactions) and exports wraparound_report.json.
  4. Condition Branching: The evaluate_risk_condition flowable task (io.kestra.plugin.core.flow.If) branches based on whether any database breached warning boundaries.
  5. Slack Alert Dispatch: When risk is flagged, alert_dba_team_on_wraparound_risk (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) delivers an actionable triage card with step-by-step remediation advice.
  6. Audit Manifest: The export_wraparound_manifest task records execution state for compliance records.

Architecture diagram

flowchart TD
    A[Schedule: Daily 03:00 UTC] --> B[query_database_freeze_horizon: PostgreSQL]
    B --> C[analyze_wraparound_risk: Python Risk Analyzer]
    C --> D{Wraparound Threshold Breached?}
    D -- Yes --> E[alert_dba_team_on_wraparound_risk: Slack]
    D -- No --> F[log_compliant_wraparound_status: Log]
    E --> G[export_wraparound_manifest: Return JSON]
    F --> G

Use cases

  • Disaster Prevention: Prevent catastrophic read-only database shutdowns triggered by transaction ID wraparound.
  • Multi-Database Cluster Auditing: Continuously scan all databases in a PostgreSQL instance for lagging autovacuum freezing.
  • Proactive Maintenance Window Planning: Identify databases requiring manual VACUUM FREEZE during off-peak hours.

What you get

  • Early detection of transaction wraparound accumulation months before emergency shutdown.
  • Automated cluster-wide catalog inspection covering all connectable databases.
  • Precise capacity percentages and remaining transaction counts formatted for on-call engineers.
  • Exportable JSON diagnostic artifacts for incident post-mortems.

Who it is for

  • Lead Database Administrators (DBAs) responsible for PostgreSQL database uptime.
  • Site Reliability Engineers maintaining mission-critical relational data stores.
  • Infrastructure Architects managing high-write OLTP workloads.

Why orchestrate this with Kestra

Monitoring internal PostgreSQL freeze limits through standard APM tools often requires complex custom agent scripts. Kestra combines native PostgreSQL JDBC connectivity, isolated container execution, and rich Slack integrations into a declarative workflow that DBAs can audit and schedule effortlessly.

Inputs

Name Type Default Description
postgres_url STRING jdbc:postgresql://... JDBC URL of the target PostgreSQL database cluster.
postgres_username STRING db_monitor Database monitoring user with catalog access.
freeze_max_age_warning_threshold INT 1500000000 Warning transaction age (default 1.5 billion).
slack_channel STRING #dba-alerts Slack channel destination for alerts.

Expected outputs

  • {{ outputs.analyze_wraparound_risk.vars.wraparound_risk_detected }}: Boolean flag indicating if any database breached threshold.
  • {{ outputs.analyze_wraparound_risk.vars.highest_age_database }}: Name of the database with the oldest freeze age.
  • {{ outputs.analyze_wraparound_risk.vars.highest_age_value }}: Current transaction age of the top offender.
  • {{ outputs.analyze_wraparound_risk.outputFiles['wraparound_report.json'] }}: Complete JSON diagnostic report.

Prerequisites

  • PostgreSQL cluster accessible via JDBC (port 5432).
  • Database user credentials stored in Kestra secrets.
  • Slack Incoming Webhook configured for your DBA operations channel.

Secrets

  • POSTGRES_PASSWORD: Password for the PostgreSQL database user.
  • SLACK_WEBHOOK_URL: Slack Incoming Webhook endpoint URL.

Quick start

  1. Configure POSTGRES_PASSWORD and SLACK_WEBHOOK_URL in your Kestra namespace secrets.
  2. Import this flow YAML into your Kestra instance.
  3. Click Execute in the UI to run an initial cluster transaction age audit.
  4. Review execution outputs to inspect calculated transaction ages and percentages.

Common pitfalls and troubleshooting

  • Long-Running Transactions: Active transactions or orphaned prepared transactions (pg_prepared_xacts) hold back the global freeze horizon; investigate idle transactions alongside table freezes.
  • Multixact Wraparound: In PostgreSQL clusters with heavy row-level locking (SELECT FOR UPDATE), check age(datminmxid) in addition to datfrozenxid.
  • Autovacuum Worker Starvation: Ensure autovacuum_max_workers and autovacuum_vacuum_cost_limit are tuned to prevent vacuum backlog accumulation.

How to extend

  • Add io.kestra.plugin.jdbc.postgresql.Query to inspect individual table ages via pg_class.relfrozenxid for the highest-age database.
  • Automatically scale up autovacuum_vacuum_cost_limit via ALTER SYSTEM during scheduled weekend maintenance windows.
  • Integrate with PagerDuty for critical severity alerts when age exceeds 1.8 billion transactions.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.