Protect a database
WAL & triggers
These are the other paths for a database — used when you can't put the wire proxy in front of it, or when you also need to catch writes from non-agent sources.
One command picks the strategy
export GMONK_DATABASE_URL="…gmonk's own store…" # set by the Docker stack
export GMONK_TARGET_URL="…the database to protect…"
gmonk protect-db protect-db detects whether the target is the same
Postgres instance as gmonk's store or a separate one, and chooses:
| Target | Mechanism | Notes |
|---|---|---|
| Co-located (owned dev, self-managed, same instance) | WAL if logical decoding is on, otherwise in-database triggers | Triggers are the most precise — joins, cascades and range updates all reverse correctly — and are agent-agnostic: psql, an ORM and app code are all captured. |
| Separate (managed RDS, Cloud SQL, any other instance) | WAL only | gmonk touches the target for the replication slot and REPLICA IDENTITY only — nothing in the write path, no gmonk objects in your database. If WAL can't be activated it reports the target NOT protected rather than installing anything. |
Exit status: 0 protected · 2 protected, but some
tables have no primary key and can't be reversed row-by-row
(reported by name) · 1 not protected or refused.
Enabling logical decoding
gmonk never calls a cloud API, needs no cloud credentials, and never
reboots anything. It detects, then instructs. protect-db
connects to the target read-only and checks wal_level and
whether it can create a replication slot:
- Ready — it sets capture up and registers the target.
- Something's missing — it prints the exact change for your
provider (an RDS parameter group, a
gcloudflag, apostgresql.confline, aGRANT) and exits non-zero. Apply it with your own tooling, then re-run. - Can't tell — it says so and asks you to verify, rather than assuming.
Draining
Co-located targets drain automatically as the agent works. For a separate target the slot lives on the target, so run the drainer — it reads the registry and services every protected target:
gmonk wal-drain # one pass
gmonk wal-drain --watch 15 # continuous; bounds WAL retention (run as a sidecar)
The drain is crash-safe (peek-then-advance: a failed write is retried, never
lost). Add tables later by re-running protect-db, which is
idempotent.
Stop protecting a database
gmonk unprotect-db --target-url "$GMONK_TARGET_URL"
# drops the slot, resets REPLICA IDENTITY, removes triggers (co-located), clears the registry Lower-level primitives
Behind protect-db, still available directly:
gmonk sql-install accounts # add a capture trigger to one owned table
gmonk wal-protect accounts # REPLICA IDENTITY FULL on one table (metadata only)
gmonk wal-setup # create the replication slot
gmonk sql-exec "UPDATE accounts SET balance = balance - 30 WHERE id = 1"