Skip to content

Commit 25cb245

Browse files
paudleyCopilot
andauthored
More extensions (#9)
* feat(extensions): bundle baseline observability plugins * feat(extensions): integrate pg_partman automation * feat(partman): add CLI wrappers for maintenance and provisioning * feat(postgis): bundle geocoder and routing extensions * feat(hypopg): enable hypothetical index analysis by default * feat(asyncq): add CLI bootstrap for built-in job queue * feat(version): add version-status reporting * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * docs: credit new extension ecosystems * fix: normalize uuid-ossp quoting * chore: tidy typing for version status helper * fix(asyncq): harden schema quoting * fix(asyncq): use format for search_path quoting * refactor: centralize default extension list * refactor(pg_partman): share bootstrap helper * feat(version): support authenticated GitHub lookup * fix(audit): sanitize buffer cache limit * fix(asyncq): enforce worker ownership on complete/fail * Update scripts/lib/async_queue.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/manage.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * fix: quote extension names during bootstrap * style(version): move urllib import to module scope * Update scripts/manage.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/lib/partman.sh Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> * Update scripts/version_status.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Patrick Audley <paudley@blackcat.ca> --------- Signed-off-by: Patrick Audley <paudley@blackcat.ca> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 49f2296 commit 25cb245

17 files changed

Lines changed: 1569 additions & 43 deletions

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ TZ=UTC
4141

4242
# Daily maintenance tuning (optional)
4343
# DAILY_PG_STAT_LIMIT=100
44+
# DAILY_BUFFERCACHE_LIMIT=50
4445
# DAILY_DEAD_TUPLE_THRESHOLD=100000
4546
# DAILY_DEAD_TUPLE_RATIO=0.2
4647
# DAILY_REPLICATION_LAG_THRESHOLD=300

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The root directory contains `docker-compose.yml`, `.env.example`, and the long-f
1111
## Build, Test, and Development Commands
1212
`docker compose build postgres` rebuilds the custom image after modifying `postgres/Dockerfile` or config templates. `docker compose up -d` provisions the database stack using the active `.env`. Use `docker compose logs postgres` to inspect startup output and health checks. Run `./scripts/manage.sh psql -d app_main -U app_user` for an interactive shell, `./scripts/manage.sh backup --type=full` to seed the pgBackRest repository, `./scripts/manage.sh pgtune-config` to generate host-specific overrides in `postgresql.pgtune.conf`, `./scripts/manage.sh pgbadger-report --since "yesterday"` to produce HTML log analytics under `/backups`, and schedule `./scripts/manage.sh daily-maintenance --root ./backups/daily` nightly to capture dumps/logs and prune old runs. The CI workflow (`.github/workflows/ci.yml`) also runs `python -m pytest -k full_workflow`; mirror that smoke test before shipping meaningful changes.
1313

14-
After manual changes, run `./scripts/manage.sh config-check` to ensure rendered configs still match the templates. The audit helpers (`audit-roles`, `audit-security`, `audit-extensions`, `audit-autovacuum`, `audit-replication`, `audit-cron`, `audit-squeeze`) stream CSV/text reports to stdout or write directly under `/backups` with `--output` so you can diff posture over time. Capture an on-demand `pg_stat_statements` snapshot with `snapshot-pgstat --output /backups/pg_stat_manual.csv` and diff it later via `diff-pgstat --base A --compare B` when chasing query regressions, and add `--verify` to `backup` invocations to restore the latest backup into a throwaway directory for checksum validation. Use `exercise-extensions` / `pgtap-smoke` as pre-flight checks before shipping code that depends on pgvector, PostGIS, or Apache AGE features. When reclaiming space, reach for `compact --level 1/2` to review autovacuum & pg_squeeze output, `compact --level 3 --tables schema.table` for a targeted pg_repack run, and reserve `compact --level 4 --scope ... --yes` (VACUUM FULL) for scheduled downtime. Cron already handles nightly pg_squeeze refreshes, a `VACUUM (ANALYZE, SKIP_LOCKED, PARALLEL 4)` pass, and `pg_stat_statements_reset()` at 04:00 UTC. Set `DAILY_EMAIL_REPORT=true` plus `DAILY_REPORT_RECIPIENT` in `.env` if you want the HTML maintenance report mailed via `sendmail`.
14+
After manual changes, run `./scripts/manage.sh config-check` to ensure rendered configs still match the templates. The audit helpers (`audit-roles`, `audit-security`, `audit-extensions`, `audit-autovacuum`, `audit-replication`, `audit-cron`, `audit-squeeze`, `audit-buffercache`) stream CSV/text reports to stdout or write directly under `/backups` with `--output` so you can diff posture over time. Capture an on-demand `pg_stat_statements` snapshot with `snapshot-pgstat --output /backups/pg_stat_manual.csv` (or grab the buffer cache distribution via `audit-buffercache`) and diff it later via `diff-pgstat --base A --compare B`. Add `--verify` to `backup` invocations to restore the latest backup into a throwaway directory for checksum validation. Use `exercise-extensions` / `pgtap-smoke` as pre-flight checks before shipping code that depends on the bundled extensions (vector, PostGIS, AGE, pgcrypto, citext, hstore, pg_partman, etc.). Reach for the dedicated pg_partman helpers when managing partition sets: `partman-show-config` enumerates tracked parents, `partman-maintenance` forces `run_maintenance_proc()`, and `partman-create-parent` wraps `create_parent()` with safe defaults. Need a lightweight job queue? `async-queue bootstrap` wires up the `asyncq` schema plus helper functions so workers can call `asyncq.dequeue` / `asyncq.complete` without extra tooling. Use `version-status` (or check the nightly `version_status.csv`) to spot drift between installed components and upstream releases. When reclaiming space, reach for `compact --level 1/2` to review autovacuum & pg_squeeze output, `compact --level 3 --tables schema.table` for a targeted pg_repack run, and reserve `compact --level 4 --scope ... --yes` (VACUUM FULL) for scheduled downtime. Cron already handles nightly pg_squeeze refreshes, hourly `pg_partman_bgw` maintenance (targeting the `postgres` database), a `VACUUM (ANALYZE, SKIP_LOCKED, PARALLEL 4)` pass, and `pg_stat_statements_reset()` at 04:00 UTC. Set `DAILY_EMAIL_REPORT=true` plus `DAILY_REPORT_RECIPIENT` in `.env` if you want the HTML maintenance report mailed via `sendmail`; adjust `DAILY_BUFFERCACHE_LIMIT` to control how many relations are captured per snapshot.
1515

1616
## Coding Style & Naming Conventions
1717
Shell scripts should follow the Google Shell Style Guide: `#!/usr/bin/env bash`, `set -euo pipefail`, two-space indentation, and lowercase `snake_case` function names. Name init scripts with zero-padded prefixes (`01-init-db-user-creation.sh`) to enforce execution order. Keep environment variables upper snake case and explain new ones in `.env.example`. Template files should remain `.tpl` and consume `${VAR}` placeholders only.

README.md

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,25 @@ A reproducible PostgreSQL 17 platform delivered as code. core_data builds a hard
2424
- PgBackRest repository and PostgreSQL data directories mount from the host for durable backups and WAL archival.
2525
- CI smoke test (`python -m pytest -k full_workflow`) provisions a stack, exercises critical commands, and verifies upgrade safety.
2626

27+
### Default Extension Bundle
28+
core_data provisions a batteries-included extension stack in every non-template database at init time:
29+
30+
- **Performance & Observability**`pg_stat_statements`, `auto_explain`, `pg_buffercache`.
31+
- **Security & Compliance**`pgaudit`, `pgcrypto`, `"uuid-ossp"`.
32+
- **Developer Ergonomics**`hstore`, `citext`, `pg_trgm`, `btree_gin`, `btree_gist`, `hypopg`.
33+
- **Connectivity**`postgres_fdw`, `dblink`.
34+
- **Spatial, Vector, Graph**`postgis`, `postgis_raster`, `postgis_topology`, `vector`, `age`.
35+
- **Maintenance & Testing**`pg_cron` (kept in the `postgres` database), `pg_partman`, `pg_repack`, `pg_squeeze`, `pgstattuple`, `pgtap`.
36+
- **Geospatial Extras**`postgis_tiger_geocoder`, `address_standardizer`, `address_standardizer_data_us`, `pgrouting`, `fuzzystrmatch`.
37+
38+
The same bundle is installed into `template1` so freshly created databases inherit the tooling automatically.
39+
40+
`pg_partman_bgw` is preloaded with a one-hour interval targeting the `postgres` database under the `postgres` superuser. Adjust `pg_partman_bgw.dbname`/`role` in `postgresql.conf.tpl` (or via `postgresql.pgtune.conf`) if you manage partitions from a different control schema.
41+
42+
Use `./scripts/manage.sh partman-show-config` to inspect tracked parents, `partman-maintenance` to run `run_maintenance_proc()` on demand, and `partman-create-parent schema.table control_column '1 day'` to bootstrap new partition sets without hand-writing SQL.
43+
44+
Run `./scripts/manage.sh async-queue bootstrap` when you want a lightweight background-job queue. It provisions an `asyncq.jobs` table plus helpers (`enqueue`, `dequeue`, `complete`, `fail`, `extend_lease`) that rely on `FOR UPDATE SKIP LOCKED`, `pg_notify`, and UUID leasing. Point a worker at the queue with `SELECT * FROM asyncq.dequeue('default');` in a loop and call `asyncq.complete(...)` or `asyncq.fail(...)` as you process jobs.
45+
2746
## Quick Start
2847
1. Copy the template: `cp .env.example .env` and customize credentials, host paths, and network settings (keep the generated `.env` local and untracked).
2948
2. Build and start the stack:
@@ -73,17 +92,23 @@ Keep `data/` out of version control—it holds live cluster state and backup arc
7392
| `audit-replication` | Summarise follower lag and sync state. |
7493
| `audit-cron` / `audit-squeeze` | Inspect pg_cron schedules and pg_squeeze activity tables. |
7594
| `audit-index-bloat` | Estimate index bloat using pgstattuple (supports `--min-size-mb`). |
95+
| `audit-buffercache` | Snapshot shared buffer usage per relation (supports `--limit`). |
7696
| `audit-schema` | Snapshot schema metadata for drift detection. |
7797
| `snapshot-pgstat` | Capture a `pg_stat_statements` baseline (CSV output) for performance trending. |
7898
| `diff-pgstat --base --compare` | Diff two snapshots (CSV-in/CSV-out) to highlight hot queries. |
7999
| `compact --level N` | Layered bloat management: 1=autovacuum audit, 2=pg_squeeze refresh, 3=pg_repack (needs `--tables`), 4=VACUUM FULL (needs `--yes`). |
80-
| `exercise-extensions` | Smoke-test pgvector, PostGIS, and Apache AGE features. |
81-
| `pgtap-smoke` | Run a micro pgTap plan to confirm key extensions are registered. |
100+
| `exercise-extensions` | Smoke-test the core extension bundle (vector, PostGIS, AGE, citext, hstore, pgcrypto, hypopg, pg_partman, etc.). |
101+
| `pgtap-smoke` | Run a micro pgTap plan to confirm key extensions (including hypopg/pg_partman) are registered. |
102+
| `async-queue bootstrap` | Install the lightweight async queue schema (`asyncq`) with enqueue/dequeue helpers. |
103+
| `partman-maintenance` | Invoke `run_maintenance_proc()` for the selected database (defaults to `POSTGRES_DB`). |
104+
| `partman-show-config` | Print rows from `part_config` (optionally filter by `--parent schema.table`). |
105+
| `partman-create-parent` | Wrap `create_parent` to bootstrap managed partitions without manual SQL. |
106+
| `version-status` | Compare installed Postgres/extension versions with upstream releases (CSV via `--output`). |
82107
| `upgrade --new-version` | Orchestrate pgautoupgrade (takes backups, validates base image, restarts). |
83108

84109
The CLI sources modular helpers from `scripts/lib/` so each function can be imported by tests or future automation.
85110

86-
`daily-maintenance` now emits a richer bundle under `backups/daily/<YYYYMMDD>/`, including `pg_stat_statements` snapshots, role/extension/autovacuum/replication CSVs, pg_cron schedules, pg_squeeze activity, and a security checklist alongside logs, dumps, pgBadger HTML, and pgaudit summaries. Pair those reports with `config-check` to keep the rendered configs aligned with the templates. Tune the thresholds via `DAILY_PG_STAT_LIMIT`, `DAILY_DEAD_TUPLE_THRESHOLD`, `DAILY_DEAD_TUPLE_RATIO`, and `DAILY_REPLICATION_LAG_THRESHOLD` as needed.
111+
`daily-maintenance` now emits a richer bundle under `backups/daily/<YYYYMMDD>/`, including `pg_stat_statements` snapshots, `pg_buffercache` heatmaps, role/extension/autovacuum/replication CSVs, pg_cron schedules, pg_squeeze activity, and a security checklist alongside logs, dumps, pgBadger HTML, and pgaudit summaries. The workflow also runs `partman.run_maintenance_proc()` across each database so freshly created partitions land even if the background worker interval has not elapsed, and it records any version drift in `version_status.csv` (focusing on out-of-date components). Pair those reports with `config-check` to keep the rendered configs aligned with the templates. Tune the thresholds via `DAILY_PG_STAT_LIMIT`, `DAILY_BUFFERCACHE_LIMIT`, `DAILY_DEAD_TUPLE_THRESHOLD`, `DAILY_DEAD_TUPLE_RATIO`, and `DAILY_REPLICATION_LAG_THRESHOLD` as needed.
87112

88113
Nightly cron jobs also refresh pg_squeeze targets, reset `pg_stat_statements`, and run a safe `VACUUM (ANALYZE, SKIP_LOCKED, PARALLEL 4)` so statistics stay current without blocking hot tables.
89114

@@ -105,7 +130,7 @@ All runs write logs under `backups/` for auditing (`pg_repack-*.log`, `vacuum-fu
105130
- **CI Workflow:** `.github/workflows/ci.yml` builds the image, runs `python -m pytest -k full_workflow`, and uploads generated backups for inspection.
106131
- **Smoke Test:** `tests/test_manage.py` spins up a disposable environment, exercises key CLI commands (including `daily-maintenance`, pgBackRest, and `upgrade`), and tears everything down. Run locally with `python -m pytest -k full_workflow` (Docker required).
107132
- **Fast Tests:** `tests/test_lightweight.py` validates offline flows like help output and the vendored tooling without needing Docker.
108-
- **Extension Smoke:** `./scripts/manage.sh exercise-extensions --db <name>` plus `pgtap-smoke` provide quick feedback that pgvector, PostGIS, Apache AGE, and pgTap are ready for use.
133+
- **Extension Smoke:** `./scripts/manage.sh exercise-extensions --db <name>` plus `pgtap-smoke` provide quick feedback that the entire core extension bundle (vector/PostGIS/AGE/hstore/citext/pgcrypto/pg_partman/etc.) is ready for use.
109134
- **Documentation:** `AGENTS.md` offers contributor runbooks and on-call notes.
110135

111136
## Credits
@@ -118,9 +143,12 @@ Thank you to the maintainers and communities behind the components that make cor
118143
- [pg_cron](https://github.com/citusdata/pg_cron) – database-native scheduling.
119144
- [pg_squeeze](https://github.com/cybertec-postgresql/pg_squeeze) – automatic bloat mitigation.
120145
- [pgvector](https://github.com/pgvector/pgvector) – high-dimensional vector search.
121-
- [PostGIS](https://postgis.net/) – spatial superpowers for PostgreSQL.
146+
- [PostGIS](https://postgis.net/) – spatial superpowers for PostgreSQL (including Tiger Geocoder & Address Standardizer).
147+
- [pgRouting](https://pgrouting.org/) – network routing & graph analysis atop PostGIS.
122148
- [Apache AGE](https://age.apache.org/) – graph database extension.
123149
- [pgaudit](https://github.com/pgaudit/pgaudit) – enhanced auditing.
150+
- [pg_partman](https://github.com/pgpartman/pg_partman) – automated time/ID partition management.
151+
- [HypoPG](https://github.com/HypoPG/hypopg) – hypothetical index exploration for query tuning.
124152
- [pg_repack](https://github.com/reorg/pg_repack) & [pgtap](https://github.com/theory/pgtap) – maintenance & testing extensions.
125153

126154
Their work powers the database-as-code experience delivered by core_data.

0 commit comments

Comments
 (0)