Skip to main content
RunBook Academy

PostgreSQLXV · High Availability, Failover and Disaster RecoveryHA

Patroni as one implementation — concepts first

Advanced⏱ ~30 min

What you'll learn

  • Map Patroni components onto the six responsibilities
  • Explain the ttl, loop_wait and retry_timeout relationship
  • Understand how the leader lease produces fencing
  • Recognise what Patroni does not solve

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

Patroni is the most widely deployed PostgreSQL HA solution. This lesson is about its concepts rather than its installation, because the concepts transfer and the installation instructions do not.

The components

A Patroni agent on each database host. It starts and stops PostgreSQL, checks its health locally, and is the only thing that should start it — lesson XV-04’s rule about systemd.

A distributed configuration store (DCS) — etcd, Consul or ZooKeeper. It holds the leader lease and the cluster’s intended configuration. It runs on its own nodes, in its own failure domains.

A REST API on each agent, which reports whether that node is the leader and is what a proxy or load balancer queries for routing.

Mapping onto lesson XV-04’s six responsibilities:

ResponsibilityPatroni
DetectAgent health-checks its local PostgreSQL
DecideLeader lease in the DCS; a majority is required
FenceLeader demotes itself when it cannot renew the lease
PromoteAgent calls PostgreSQL’s promotion
RerouteREST API endpoints a proxy can query
RejoinAgent runs pg_rewind or a fresh base backup

All six. That is what “an HA stack” means concretely.

The timing constraint

Four settings govern everything, and the documentation states a relationship between three of them.

SettingDefaultWhat it is
ttl30 s (min 20)The TTL on the leader lock. “The length of time before initiation of the automatic failover process.”
loop_wait10 s (min 1)How long the agent’s loop sleeps between iterations
retry_timeout10 s (min 3)Timeout for DCS and PostgreSQL retries. “DCS or network issues shorter than this will not cause Patroni to demote the leader.”
primary_start_timeout300 sHow long a primary may take to recover from failures before failover is triggered

How the lease produces fencing

This is the mechanism from lesson XV-03, concretely:

  1. The leader holds a lock in the DCS with a TTL of ttl seconds.
  2. It refreshes that lock on every loop iteration.
  3. If it cannot refresh — for any reason — it demotes its own PostgreSQL. It does not wait to be told; it acts on its own inability to confirm it is still the leader.
  4. Other agents cannot acquire the leader lock until the TTL expires.

Step 3 is the fencing, and step 4 is what makes it safe. By the time any other node can take the lock, the old leader has already demoted itself, because it began demoting the moment it lost contact and the TTL has since elapsed.

The guarantee comes from arithmetic on timeouts rather than from reaching the failing node — which is why it holds during a network partition, the case where every cooperation-based mechanism fails.

Choosing a candidate

maximum_lag_on_failover is “the maximum bytes a follower may lag to be able to participate in leader election.”

This is the setting that stops a stale standby being promoted, and it is the point at which an availability decision becomes a data loss decision. A tight value means a failover may not be possible when the only surviving replica is behind; a loose one means promoting a replica that is missing more than you would have accepted.

synchronous_mode (off, on, quorum) makes Patroni manage synchronous_standby_names itself, so that only a standby known to be current can be elected. That is the zero-RPO configuration, and it carries the availability cost lesson XIV-05 measured.

What to take from this

  • Patroni supplies all six responsibilities: agent per node, DCS holding a leader lease, REST API for routing.
  • loop_wait + 2 × retry_timeout ≤ ttl. Documented, and the defaults meet it exactly at 10 + 20 = 30.
  • Tuning ttl alone to fail over faster produces spurious failovers.
  • Fencing is the leader demoting itself when it cannot renew, plus a TTL that must expire before anyone else can take the lock.
  • maximum_lag_on_failover is where availability becomes an RPO decision.
  • Patroni does not solve routing, pooling, backups, or your locks.
  • Measured: promotion is 89 ms. The RTO is spent almost entirely elsewhere.

Cross-course references

  • Kubernetes for Production Sysadmins — Part LXVI (etcd) and Part LXVII (etcd quorum) cover the distributed configuration store Patroni depends on, including the failure mode where the store is healthy and the network to it is not.
  • Linux for Production Sysadmins — Part LV (Pacemaker and Corosync) covers an older stack solving the same problem, which makes the trade-offs easier to see.
  • Ansible for Production Sysadmins — Part XXXVI (Drift) covers keeping the configuration Patroni owns and the configuration you own from overwriting each other.

Quiz

Knowledge check · 6 questions

  1. Q1. A team lowers Patroni's ttl from 30 to 15 seconds to improve RTO, leaving loop_wait and retry_timeout at their defaults. What follows?

  2. Q2. How does a leader lease produce fencing during a network partition?

  3. Q3. An automated failover is measured at 60 seconds end to end. Where is that time actually spent?

  4. Q4. Which problems does Patroni leave for something else to solve? Select all that apply.

  5. Q5. maximum_lag_on_failover is the setting at which an availability decision becomes a data-loss decision.

  6. Q6. Explain the purpose of the constraint loop_wait + 2 × retry_timeout ≤ ttl.

Passing score: 75%. Answers are checked in this browser.