Chapter 12: postjevsql-sidecar/cli, the one engine

This is the binary, postjevsql-sidecar, and the only part of the sidecar that talks to Postgres. It takes the config from chapter 11 and one of three commands:

postjevsql-sidecar [--sidecar <conninfo>] <config.toml> converge
postjevsql-sidecar [--sidecar <conninfo>] <config.toml> sync [--apply]
postjevsql-sidecar <config.toml> serve [-- <postgres options>…]
  • converge creates postgres_fdw and postjevsql on the sidecar, declares the foreign server with exactly the configured options (so an option someone added by hand is dropped), and declares the user mappings: a password from its secret, or PG18's use_scram_passthrough when none is given.
  • sync reads the target's catalog and prints the plan from sync::plan. sync --apply applies it in one transaction, unless a change touches something a sidecar view, BEGIN ATOMIC function or grant depends on (pg_depend), in which case it names each dependent and changes nothing.
  • serve is the container image's entrypoint: initialise $PGDATA if it is empty, start Postgres, wait for it, converge, sync --apply, stop it with pg_ctl stop, and then exec postgres in its own place, so the server is PID 1 and gets the container runtime's signals directly. A refusal stops the server and exits non-zero with the reason.

--sidecar is the conninfo of the sidecar itself; by default host=/run/postgresql user=postgres dbname=postgres. Every secret is resolved before anything connects, so a config that names a secret twice is refused first.

sequenceDiagram
  participant CLI as postjevsql-sidecar sync
  participant S as Sidecar Postgres
  participant T as Target (through the foreign server)
  CLI->>S: BEGIN, then CREATE SCHEMA postjevsql_sync_0
  CLI->>S: as the first mapping's user, IMPORT FOREIGN SCHEMA public FROM SERVER target INTO postjevsql_sync_0
  S->>T: read the catalog
  T-->>S: the target's tables, as postgres_fdw imports them
  CLI->>S: read the scratch tables and the existing foreign tables
  CLI->>S: ROLLBACK
  CLI->>CLI: sync::plan, then (with --apply) check pg_depend and apply in one transaction

Aside. Notice that the CLI never connects to the target. It reads the target's catalog through the sidecar's own foreign server, importing it into a scratch schema inside a transaction that is rolled back. So there is no second connection to configure, no second set of credentials, and the column types it compares are exactly the ones postgres_fdw would import. One cost, stated: a function with a string body is not tracked by pg_depend, so a change it depends on is not found.

Try it. nix develop -c buck2 test //tests:sidecar_cli starts a throwaway target and a throwaway sidecar and checks that converge declares exactly the configured server, that sync changes nothing, that sync --apply changes only what differs, and that a change a view depends on is refused with nothing applied.

For the people who maintain it

FileWhat
main.rsThe three commands, the secret resolution before connecting, the catalog read through IMPORT FOREIGN SCHEMA, the pg_depend check, and serve's start, converge, stop and exec. Built as //crates/postjevsql-sidecar:cli, packaged by nix/sidecar-cli.nix.

← Previous: Chapter 11, postjevsql-sidecar/src/ · Up: postjevsql-sidecar · Next: Chapter 13, tests/ →