Operations

What to know when running PgCache in production: how it behaves across restarts, how its replication slot affects your origin database, how to warm a cold cache during a cutover, and how it fits into a highly-available setup.

Restart and Recovery

PgCache’s cache is ephemeral. The cache database is dropped and recreated every time PgCache starts, so after any restart the cache begins empty and repopulates as queries arrive. There is no on-disk cache state to preserve, migrate, or corrupt.

What this means operationally:

  • A restart never serves stale data. The cache is rebuilt from scratch and resynchronized with the origin via logical replication, so a restart cannot resurrect outdated rows.
  • The cache is cold immediately after a restart. Until queries repopulate it, requests are forwarded to the origin and the cache hit ratio climbs from zero back to its steady state. See Cache warm-up to pre-populate on startup.

The Replication Slot

PgCache keeps the cache consistent by consuming a logical replication slot on the origin. The slot’s lifecycle directly affects origin disk usage, so it’s worth understanding.

  • On startup, PgCache creates the replication slot if it does not already exist, and recreates its publication.
  • On graceful shutdown, PgCache drops both the slot and the publication. The origin can then reclaim any WAL the slot was retaining.
  • On a crash or hard kill (SIGKILL, OOM, instance termination), the shutdown cleanup does not run, so the replication slot is left behind on the origin.

Why a leftover slot matters

A logical replication slot pins WAL on the origin — PostgreSQL will not remove WAL segments the slot has not yet confirmed. While PgCache is running and consuming the slot, the retained WAL is bounded by replication lag. But if PgCache crashes and stays down, the orphaned slot keeps pinning WAL, and the origin’s disk usage grows unbounded until either:

  • PgCache restarts and resumes consuming the slot (it reuses the existing slot by name), or
  • the slot is dropped manually on the origin.

Mitigation:

  • Monitor pgcache.cdc.lag_bytes, and watch the slot directly on the origin:

    SELECT slot_name, active,
           pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes
    FROM pg_replication_slots;
  • Alert on a slot that is active = false with growing retained_bytes — that means PgCache is down while its slot is still pinning WAL on the origin.

  • When you permanently decommission a PgCache instance (rather than restart it), drop its slot on the origin so the WAL can be reclaimed:

    SELECT pg_drop_replication_slot('your_slot_name');

Cache Warm-Up

By default (admission_threshold = 1) a query is cached the first time it is seen, so the cache warms naturally as traffic arrives — the only cost is one forwarded request per distinct query while the cache is cold.

For a planned cutover where you want hot paths cached before you shift traffic, pre-populate them on startup with pinned queries:

# Pre-populate and protect these at startup
pinned_queries = [
    "SELECT * FROM settings",
    "SELECT * FROM products WHERE active = true",
]

# Shorthand to pin entire tables (expands to SELECT * FROM <table>)
pinned_tables = ["categories", "feature_flags"]

Pinned queries are populated at startup, protected from eviction, and automatically re-admitted after a CDC invalidation. See Configuration for the full reference. PgCache does not currently seed the cache automatically from pg_stat_statements or query logs.

High Availability

PgCache is a stateless proxy in front of your origin database — all durable data lives on the origin, and the cache holds only a consistent, reconstructable copy.

  • Each instance is independent. The cache is neither shared between instances nor persisted, so an instance can be replaced at any time; its replacement warms from scratch.
  • On instance failure, route traffic back to the origin (or to another PgCache instance) while it restarts. Because the cache is consistent and ephemeral, failover never risks serving stale data.
  • Running multiple instances for redundancy is supported. Give each instance a distinct slot_name and publication_name so their replication slots don’t collide on the origin.

For where PgCache sits relative to PgBouncer or RDS Proxy, see Connection Pooler Compatibility.