@evertonferreira96/agents 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/api.md +45 -0
- package/.claude/agents/app.md +41 -0
- package/.claude/agents/architect.md +49 -0
- package/.claude/agents/infra.md +27 -0
- package/.claude/agents/product.md +58 -0
- package/.claude/agents/quick.md +33 -0
- package/.claude/agents/security.md +39 -0
- package/.claude/agents/ui.md +54 -0
- package/.claude/agents/verifier.md +56 -0
- package/.claude/agents/web.md +41 -0
- package/.claude/hooks/config-update-check.mjs +14 -0
- package/.claude/hooks/context-budget.mjs +51 -0
- package/.claude/hooks/graphify-update.sh +16 -0
- package/.claude/hooks/guard-bash.sh +64 -0
- package/.claude/hooks/orchestrator-guard.sh +49 -0
- package/.claude/hooks/post-compact.sh +26 -0
- package/.claude/hooks/readonly-guard.sh +54 -0
- package/.claude/hooks/stop-verify.sh +52 -0
- package/.claude/rules/api.md +21 -0
- package/.claude/rules/db.md +9 -0
- package/.claude/rules/delivery-diagram.md +16 -0
- package/.claude/rules/git-workflow.md +34 -0
- package/.claude/rules/graphify.md +3 -0
- package/.claude/rules/mobile.md +22 -0
- package/.claude/rules/tickets.md +9 -0
- package/.claude/rules/ui.md +14 -0
- package/.claude/rules/web.md +27 -0
- package/.claude/settings.json +114 -0
- package/.claude/skills/animate/RECIPES.md +324 -0
- package/.claude/skills/animate/SKILL.md +208 -0
- package/.claude/skills/animate/agents/openai.yaml +5 -0
- package/.claude/skills/animate-expo/RECIPES.md +385 -0
- package/.claude/skills/animate-expo/SKILL.md +264 -0
- package/.claude/skills/animate-expo/agents/openai.yaml +5 -0
- package/.claude/skills/animation-performance/SKILL.md +223 -0
- package/.claude/skills/animation-performance/agents/openai.yaml +5 -0
- package/.claude/skills/apple-design/SKILL.md +291 -0
- package/.claude/skills/apple-design/agents/openai.yaml +5 -0
- package/.claude/skills/arch-api/SKILL.md +291 -0
- package/.claude/skills/arch-api/agents/openai.yaml +3 -0
- package/.claude/skills/arch-api/references/common.md +174 -0
- package/.claude/skills/arch-api/references/contract.md +289 -0
- package/.claude/skills/arch-api/references/domain.md +301 -0
- package/.claude/skills/arch-api/references/endpoints.md +184 -0
- package/.claude/skills/arch-api/references/review.md +228 -0
- package/.claude/skills/arch-api/references/security.md +151 -0
- package/.claude/skills/arch-app/SKILL.md +278 -0
- package/.claude/skills/arch-app/agents/openai.yaml +3 -0
- package/.claude/skills/arch-app/references/navigation-session.md +257 -0
- package/.claude/skills/arch-app/references/review.md +155 -0
- package/.claude/skills/arch-app/references/screens.md +214 -0
- package/.claude/skills/arch-app/references/services.md +301 -0
- package/.claude/skills/arch-app/references/ui-mobile.md +124 -0
- package/.claude/skills/arch-db/SKILL.md +181 -0
- package/.claude/skills/arch-db/agents/openai.yaml +3 -0
- package/.claude/skills/arch-db/references/indexes-queries.md +251 -0
- package/.claude/skills/arch-db/references/migrations.md +191 -0
- package/.claude/skills/arch-db/references/modeling.md +214 -0
- package/.claude/skills/arch-db/references/mysql.md +262 -0
- package/.claude/skills/arch-db/references/pooling-ops.md +112 -0
- package/.claude/skills/arch-db/references/review.md +143 -0
- package/.claude/skills/arch-db/references/transactions-locks.md +141 -0
- package/.claude/skills/arch-web/SKILL.md +307 -0
- package/.claude/skills/arch-web/agents/openai.yaml +3 -0
- package/.claude/skills/arch-web/references/auth-session-env.md +165 -0
- package/.claude/skills/arch-web/references/blocks.md +198 -0
- package/.claude/skills/arch-web/references/cache.md +124 -0
- package/.claude/skills/arch-web/references/review.md +142 -0
- package/.claude/skills/arch-web/references/services.md +297 -0
- package/.claude/skills/arch-web/references/tests.md +159 -0
- package/.claude/skills/arch-web/references/ui-forms.md +143 -0
- package/.claude/skills/break-ui/CATALOG.md +135 -0
- package/.claude/skills/break-ui/SKILL.md +176 -0
- package/.claude/skills/break-ui/agents/openai.yaml +5 -0
- package/.claude/skills/brief/SKILL.md +91 -0
- package/.claude/skills/brief/agents/openai.yaml +3 -0
- package/.claude/skills/diagnosing-bugs/SKILL.md +138 -0
- package/.claude/skills/diagnosing-bugs/agents/openai.yaml +3 -0
- package/.claude/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
- package/.claude/skills/emil-design-eng/SKILL.md +675 -0
- package/.claude/skills/emil-design-eng/agents/openai.yaml +5 -0
- package/.claude/skills/find-animation-opportunities/SKILL.md +141 -0
- package/.claude/skills/find-animation-opportunities/agents/openai.yaml +5 -0
- package/.claude/skills/graphify/.graphify_version +1 -0
- package/.claude/skills/graphify/SKILL.md +742 -0
- package/.claude/skills/graphify/agents/openai.yaml +3 -0
- package/.claude/skills/graphify/references/add-watch.md +56 -0
- package/.claude/skills/graphify/references/exports.md +91 -0
- package/.claude/skills/graphify/references/extraction-spec.md +70 -0
- package/.claude/skills/graphify/references/github-and-merge.md +46 -0
- package/.claude/skills/graphify/references/hooks.md +33 -0
- package/.claude/skills/graphify/references/query.md +317 -0
- package/.claude/skills/graphify/references/transcribe.md +52 -0
- package/.claude/skills/graphify/references/update.md +221 -0
- package/.claude/skills/grill-me/SKILL.md +7 -0
- package/.claude/skills/grill-me/agents/openai.yaml +5 -0
- package/.claude/skills/grill-with-docs/SKILL.md +64 -0
- package/.claude/skills/grill-with-docs/agents/openai.yaml +5 -0
- package/.claude/skills/grilling/SKILL.md +30 -0
- package/.claude/skills/grilling/agents/openai.yaml +3 -0
- package/.claude/skills/handoff/SKILL.md +28 -0
- package/.claude/skills/handoff/agents/openai.yaml +5 -0
- package/.claude/skills/impeccable/SKILL.md +89 -0
- package/.claude/skills/impeccable/agents/openai.yaml +5 -0
- package/.claude/skills/impeccable/reference/adapt.md +318 -0
- package/.claude/skills/impeccable/reference/adapt.native.md +58 -0
- package/.claude/skills/impeccable/reference/android.md +46 -0
- package/.claude/skills/impeccable/reference/animate.md +89 -0
- package/.claude/skills/impeccable/reference/audit.md +137 -0
- package/.claude/skills/impeccable/reference/audit.native.md +139 -0
- package/.claude/skills/impeccable/reference/bolder.md +33 -0
- package/.claude/skills/impeccable/reference/clarify.md +94 -0
- package/.claude/skills/impeccable/reference/colorize.md +86 -0
- package/.claude/skills/impeccable/reference/component-review.md +63 -0
- package/.claude/skills/impeccable/reference/craft-floor.md +44 -0
- package/.claude/skills/impeccable/reference/craft.md +5 -0
- package/.claude/skills/impeccable/reference/critique.md +809 -0
- package/.claude/skills/impeccable/reference/degraded/asset-producer.md +42 -0
- package/.claude/skills/impeccable/reference/degraded/documenter.md +24 -0
- package/.claude/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
- package/.claude/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
- package/.claude/skills/impeccable/reference/delight.md +70 -0
- package/.claude/skills/impeccable/reference/distill.md +111 -0
- package/.claude/skills/impeccable/reference/doctor.md +54 -0
- package/.claude/skills/impeccable/reference/document.md +416 -0
- package/.claude/skills/impeccable/reference/extract.md +69 -0
- package/.claude/skills/impeccable/reference/generate.md +101 -0
- package/.claude/skills/impeccable/reference/harden.md +345 -0
- package/.claude/skills/impeccable/reference/hooks.md +113 -0
- package/.claude/skills/impeccable/reference/init.md +131 -0
- package/.claude/skills/impeccable/reference/ios.md +51 -0
- package/.claude/skills/impeccable/reference/layout.md +84 -0
- package/.claude/skills/impeccable/reference/live-setup.md +104 -0
- package/.claude/skills/impeccable/reference/live.md +325 -0
- package/.claude/skills/impeccable/reference/mode-operate.md +21 -0
- package/.claude/skills/impeccable/reference/mode-persuade.md +19 -0
- package/.claude/skills/impeccable/reference/mode-read.md +21 -0
- package/.claude/skills/impeccable/reference/new-work.md +154 -0
- package/.claude/skills/impeccable/reference/onboard.md +234 -0
- package/.claude/skills/impeccable/reference/operate.md +61 -0
- package/.claude/skills/impeccable/reference/optimize.md +258 -0
- package/.claude/skills/impeccable/reference/overdrive.md +127 -0
- package/.claude/skills/impeccable/reference/polish.md +105 -0
- package/.claude/skills/impeccable/reference/quieter.md +99 -0
- package/.claude/skills/impeccable/reference/region-map.md +26 -0
- package/.claude/skills/impeccable/reference/routing.md +24 -0
- package/.claude/skills/impeccable/reference/shape.md +59 -0
- package/.claude/skills/impeccable/reference/typeset.md +80 -0
- package/.claude/skills/impeccable/reference/visualize.md +47 -0
- package/.claude/skills/impeccable/scripts/VERSION +1 -0
- package/.claude/skills/impeccable/scripts/command-metadata.json +98 -0
- package/.claude/skills/impeccable/scripts/data/font-index-failures.json +121 -0
- package/.claude/skills/impeccable/scripts/data/font-index.json +1 -0
- package/.claude/skills/impeccable/scripts/impeccable +206 -0
- package/.claude/skills/impeccable/scripts/impeccable.cmd +214 -0
- package/.claude/skills/impeccable/scripts/live-browser-dom.js +281 -0
- package/.claude/skills/impeccable/scripts/live-browser-ignores.js +242 -0
- package/.claude/skills/impeccable/scripts/live-browser-session.js +148 -0
- package/.claude/skills/impeccable/scripts/live-browser.js +13532 -0
- package/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/.claude/skills/improve-animations/AUDIT.md +115 -0
- package/.claude/skills/improve-animations/PLAN-TEMPLATE.md +73 -0
- package/.claude/skills/improve-animations/SKILL.md +110 -0
- package/.claude/skills/improve-animations/agents/openai.yaml +5 -0
- package/.claude/skills/mobile-native/SKILL.md +311 -0
- package/.claude/skills/mobile-native/agents/openai.yaml +3 -0
- package/.claude/skills/orchestrate/SKILL.md +181 -0
- package/.claude/skills/orchestrate/agents/openai.yaml +3 -0
- package/.claude/skills/pick-ui-library/SKILL.md +85 -0
- package/.claude/skills/pick-ui-library/agents/openai.yaml +5 -0
- package/.claude/skills/ponytail/SKILL.md +52 -0
- package/.claude/skills/ponytail/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-audit/SKILL.md +103 -0
- package/.claude/skills/ponytail-audit/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-debt/SKILL.md +44 -0
- package/.claude/skills/ponytail-debt/agents/openai.yaml +3 -0
- package/.claude/skills/ponytail-review/SKILL.md +101 -0
- package/.claude/skills/ponytail-review/agents/openai.yaml +3 -0
- package/.claude/skills/postgres-best-practices/SKILL.md +42 -0
- package/.claude/skills/postgres-best-practices/agents/openai.yaml +3 -0
- package/.claude/skills/postgres-best-practices/references/backup-restore.md +372 -0
- package/.claude/skills/postgres-best-practices/references/bulk-loading.md +315 -0
- package/.claude/skills/postgres-best-practices/references/connection-pooling.md +310 -0
- package/.claude/skills/postgres-best-practices/references/hot-standby.md +221 -0
- package/.claude/skills/postgres-best-practices/references/indexing.md +318 -0
- package/.claude/skills/postgres-best-practices/references/logical-replication.md +610 -0
- package/.claude/skills/postgres-best-practices/references/major-version-upgrades.md +334 -0
- package/.claude/skills/postgres-best-practices/references/performance-diagnostics.md +553 -0
- package/.claude/skills/postgres-best-practices/references/query-optimization.md +294 -0
- package/.claude/skills/postgres-best-practices/references/query-patterns.md +566 -0
- package/.claude/skills/postgres-best-practices/references/schema-design.md +362 -0
- package/.claude/skills/postgres-best-practices/references/security-roles.md +489 -0
- package/.claude/skills/postgres-best-practices/references/transaction-isolation.md +344 -0
- package/.claude/skills/project-docs/SKILL.md +330 -0
- package/.claude/skills/project-docs/agents/openai.yaml +3 -0
- package/.claude/skills/prototype/PICKER.md +197 -0
- package/.claude/skills/prototype/SKILL.md +98 -0
- package/.claude/skills/prototype/agents/openai.yaml +5 -0
- package/.claude/skills/retro/SKILL.md +43 -0
- package/.claude/skills/retro/agents/openai.yaml +5 -0
- package/.claude/skills/review/SKILL.md +74 -0
- package/.claude/skills/review/agents/openai.yaml +3 -0
- package/.claude/skills/review/references/smells.md +23 -0
- package/.claude/skills/review-animations/SKILL.md +120 -0
- package/.claude/skills/review-animations/STANDARDS.md +187 -0
- package/.claude/skills/review-animations/agents/openai.yaml +5 -0
- package/.claude/skills/tdd/SKILL.md +38 -0
- package/.claude/skills/tdd/agents/openai.yaml +3 -0
- package/.claude/skills/tdd/mocking.md +59 -0
- package/.claude/skills/tdd/tests.md +77 -0
- package/.claude/skills/triage/SKILL.md +58 -0
- package/.claude/skills/triage/agents/openai.yaml +3 -0
- package/.claude/skills/ui-ux-pro-max/SKILL.md +378 -0
- package/.claude/skills/ui-ux-pro-max/agents/openai.yaml +5 -0
- package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
- package/.claude/skills/writing-for-agents/SKILL.md +81 -0
- package/.claude/skills/writing-for-agents/agents/openai.yaml +3 -0
- package/.worktreeinclude +3 -0
- package/AGENTS.md +44 -0
- package/README.md +14 -2
- package/VERSION +1 -0
- package/bin/agents.mjs +45 -0
- package/docs/adr/README.md +31 -0
- package/docs/brief-template.md +3 -0
- package/docs/plans/README.md +73 -0
- package/package.json +46 -4
- package/scripts/bootstrap.mjs +188 -0
- package/scripts/check-catalog.mjs +43 -0
- package/scripts/skills-update.mjs +51 -0
- package/skills-lock.json +269 -0
- package/templates/CLAUDE.project.md +41 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# Connection Pooling Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Why connection pooling matters
|
|
5
|
+
- PgBouncer configuration
|
|
6
|
+
- Pool modes
|
|
7
|
+
- Prepared statement handling
|
|
8
|
+
- Monitoring and diagnostics
|
|
9
|
+
- Application-side pooling
|
|
10
|
+
|
|
11
|
+
## Why Connection Pooling Matters
|
|
12
|
+
|
|
13
|
+
Each PostgreSQL connection spawns a dedicated backend process (~5-10 MB of memory). Without pooling:
|
|
14
|
+
|
|
15
|
+
- 500 application instances × 10 connections each = 5,000 backend processes
|
|
16
|
+
- Memory: 5,000 × 10 MB = ~50 GB just for connection overhead
|
|
17
|
+
- Context switching degrades performance above a few hundred active backends
|
|
18
|
+
- `max_connections` must be set high, wasting shared memory
|
|
19
|
+
|
|
20
|
+
A connection pooler sits between the application and PostgreSQL, multiplexing many client connections onto fewer server connections.
|
|
21
|
+
|
|
22
|
+
### Connection Overhead
|
|
23
|
+
|
|
24
|
+
```sql
|
|
25
|
+
-- Current connections vs. limit
|
|
26
|
+
SELECT
|
|
27
|
+
count(*) AS current,
|
|
28
|
+
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max,
|
|
29
|
+
(SELECT setting::int FROM pg_settings WHERE name = 'superuser_reserved_connections') AS reserved
|
|
30
|
+
FROM pg_stat_activity;
|
|
31
|
+
|
|
32
|
+
-- Potential per-operation and per-session memory settings
|
|
33
|
+
SELECT
|
|
34
|
+
name,
|
|
35
|
+
current_setting(name) AS configured_value,
|
|
36
|
+
pg_size_bytes(current_setting(name)) AS configured_bytes
|
|
37
|
+
FROM pg_settings
|
|
38
|
+
WHERE name IN ('work_mem', 'temp_buffers')
|
|
39
|
+
ORDER BY name;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
These are not baseline allocations per backend. `work_mem` can be consumed by multiple query operations, while `temp_buffers` is allocated lazily when a session uses temporary tables.
|
|
43
|
+
|
|
44
|
+
## PgBouncer Configuration
|
|
45
|
+
|
|
46
|
+
PgBouncer is the most widely used connection pooler for PostgreSQL.
|
|
47
|
+
|
|
48
|
+
### Essential pgbouncer.ini Settings
|
|
49
|
+
|
|
50
|
+
```ini
|
|
51
|
+
[databases]
|
|
52
|
+
mydb = host=127.0.0.1 port=5432 dbname=mydb
|
|
53
|
+
|
|
54
|
+
[pgbouncer]
|
|
55
|
+
listen_addr = 0.0.0.0
|
|
56
|
+
listen_port = 6432
|
|
57
|
+
auth_type = scram-sha-256
|
|
58
|
+
auth_file = /etc/pgbouncer/userlist.txt
|
|
59
|
+
|
|
60
|
+
# Pool sizing
|
|
61
|
+
pool_mode = transaction
|
|
62
|
+
default_pool_size = 20
|
|
63
|
+
min_pool_size = 5
|
|
64
|
+
max_client_conn = 1000
|
|
65
|
+
max_db_connections = 50
|
|
66
|
+
|
|
67
|
+
# Timeouts
|
|
68
|
+
server_idle_timeout = 300
|
|
69
|
+
client_idle_timeout = 0
|
|
70
|
+
query_timeout = 0
|
|
71
|
+
query_wait_timeout = 120
|
|
72
|
+
server_login_retry = 15
|
|
73
|
+
|
|
74
|
+
# Logging
|
|
75
|
+
log_connections = 0
|
|
76
|
+
log_disconnections = 0
|
|
77
|
+
stats_period = 60
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Key Parameters
|
|
81
|
+
|
|
82
|
+
| Parameter | Recommended | Purpose |
|
|
83
|
+
|-----------|------------|---------|
|
|
84
|
+
| `default_pool_size` | 20-50 | Server connections per user/database pair |
|
|
85
|
+
| `min_pool_size` | 5 | Minimum idle server connections to keep open |
|
|
86
|
+
| `max_client_conn` | 1000-10000 | Max client connections PgBouncer accepts |
|
|
87
|
+
| `max_db_connections` | 50-100 | Hard cap on server connections per database |
|
|
88
|
+
| `reserve_pool_size` | 5 | Extra connections for burst traffic |
|
|
89
|
+
| `reserve_pool_timeout` | 3 | Seconds before using reserve pool |
|
|
90
|
+
| `query_wait_timeout` | 120 | Max time a client waits for a server connection |
|
|
91
|
+
|
|
92
|
+
### Sizing Rule of Thumb
|
|
93
|
+
|
|
94
|
+
**Server connections**: Set `default_pool_size` to roughly 2-4x the number of CPU cores on the database server. More connections don't help — they just increase lock contention and context switching.
|
|
95
|
+
|
|
96
|
+
**Client connections**: Set `max_client_conn` high enough for all application instances. PgBouncer handles thousands of idle client connections with minimal memory.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
App instances (500 clients) ──→ PgBouncer (max_client_conn=1000) ──→ PostgreSQL (pool_size=20)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Pool Modes
|
|
103
|
+
|
|
104
|
+
### Transaction Mode (Recommended for Most Applications)
|
|
105
|
+
|
|
106
|
+
```ini
|
|
107
|
+
pool_mode = transaction
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Server connection is assigned when a transaction begins and returned when it commits/rolls back. Between transactions, the connection is available to other clients.
|
|
111
|
+
|
|
112
|
+
**Compatible with**: Standard SQL, parameterized queries, most ORMs.
|
|
113
|
+
|
|
114
|
+
**NOT compatible with** (session-level features):
|
|
115
|
+
- `SET` / `RESET` (use `SET LOCAL` inside a transaction instead)
|
|
116
|
+
- `LISTEN` / `NOTIFY`
|
|
117
|
+
- SQL-level `PREPARE` / `DEALLOCATE` (use protocol-level prepared statements)
|
|
118
|
+
- `DECLARE ... WITH HOLD` cursors
|
|
119
|
+
- Temporary tables with `ON COMMIT PRESERVE ROWS`
|
|
120
|
+
- Session-level advisory locks (`pg_advisory_lock` — use `pg_advisory_xact_lock` instead)
|
|
121
|
+
- `LOAD` statement
|
|
122
|
+
|
|
123
|
+
### Session Mode
|
|
124
|
+
|
|
125
|
+
```ini
|
|
126
|
+
pool_mode = session
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Server connection is held for the entire client session. Compatible with all PostgreSQL features but offers less multiplexing benefit.
|
|
130
|
+
|
|
131
|
+
**Use when**: Application relies on session-level features (temp tables, LISTEN/NOTIFY, SET parameters).
|
|
132
|
+
|
|
133
|
+
### Statement Mode
|
|
134
|
+
|
|
135
|
+
```ini
|
|
136
|
+
pool_mode = statement
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Server connection released after every statement. Maximum multiplexing but **incompatible with multi-statement transactions**.
|
|
140
|
+
|
|
141
|
+
**Use when**: Application only runs autocommit single statements (rare).
|
|
142
|
+
|
|
143
|
+
### Choosing a Mode
|
|
144
|
+
|
|
145
|
+
| Application pattern | Recommended mode |
|
|
146
|
+
|--------------------|-----------------|
|
|
147
|
+
| Web apps, APIs, serverless | Transaction |
|
|
148
|
+
| Applications using LISTEN/NOTIFY | Session |
|
|
149
|
+
| Applications using temp tables across transactions | Session |
|
|
150
|
+
| Applications with SET session variables | Session (or refactor to `SET LOCAL`) |
|
|
151
|
+
| Simple autocommit queries | Statement |
|
|
152
|
+
|
|
153
|
+
## Prepared Statement Handling
|
|
154
|
+
|
|
155
|
+
### The Problem
|
|
156
|
+
|
|
157
|
+
SQL-level `PREPARE`/`EXECUTE` creates server-side prepared statements tied to a session. In transaction mode, the next transaction may use a different server connection where the prepared statement doesn't exist.
|
|
158
|
+
|
|
159
|
+
### Solutions
|
|
160
|
+
|
|
161
|
+
**Protocol-level prepared statements**: Most modern drivers use the PostgreSQL wire protocol's `Parse`/`Bind`/`Execute` messages, which PgBouncer (1.21+) can handle:
|
|
162
|
+
|
|
163
|
+
```ini
|
|
164
|
+
# PgBouncer 1.21+
|
|
165
|
+
max_prepared_statements = 100 # per server connection
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Driver-level configuration** to avoid SQL-level PREPARE:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
# Python psycopg: uses protocol-level by default — no change needed
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
// Node.js pg: protocol-level by default
|
|
176
|
+
const pool = new Pool({ ...config });
|
|
177
|
+
// For explicit control:
|
|
178
|
+
// statement_timeout via SET LOCAL, not SET
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```java
|
|
182
|
+
// JDBC: protocol-level by default with prepareThreshold
|
|
183
|
+
// ?prepareThreshold=5 (default: 5 uses before server-side prepare)
|
|
184
|
+
// ?prepareThreshold=0 (disable server-side prepare entirely)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
# Ruby pg: protocol-level by default
|
|
189
|
+
# ActiveRecord: no special config needed
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Monitoring and Diagnostics
|
|
193
|
+
|
|
194
|
+
### PgBouncer Admin Console
|
|
195
|
+
|
|
196
|
+
Connect to PgBouncer's admin port:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Key Commands
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
-- Pool status (most useful)
|
|
206
|
+
SHOW POOLS;
|
|
207
|
+
-- Columns: database, user, cl_active, cl_waiting, sv_active, sv_idle, sv_used, pool_mode
|
|
208
|
+
|
|
209
|
+
-- Active client and server connections
|
|
210
|
+
SHOW CLIENTS;
|
|
211
|
+
SHOW SERVERS;
|
|
212
|
+
|
|
213
|
+
-- Aggregate statistics
|
|
214
|
+
SHOW STATS;
|
|
215
|
+
-- Columns: total_xact_count, total_query_count, avg_xact_time, avg_query_time
|
|
216
|
+
|
|
217
|
+
-- Configuration
|
|
218
|
+
SHOW CONFIG;
|
|
219
|
+
|
|
220
|
+
-- Memory usage
|
|
221
|
+
SHOW MEM;
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
These commands use PgBouncer's admin protocol and fail if sent directly to PostgreSQL.
|
|
225
|
+
|
|
226
|
+
### What to Watch
|
|
227
|
+
|
|
228
|
+
| Metric | Healthy | Problem |
|
|
229
|
+
|--------|---------|---------|
|
|
230
|
+
| `cl_waiting` | 0 | > 0 = clients waiting for server connections |
|
|
231
|
+
| `sv_active` | < pool_size | = pool_size = pool exhausted |
|
|
232
|
+
| `sv_idle` | > 0 | 0 = no spare connections |
|
|
233
|
+
| `avg_xact_time` | < 100ms | High = long transactions hogging connections |
|
|
234
|
+
| `avg_wait_time` | 0 | > 0 = pool too small or transactions too long |
|
|
235
|
+
|
|
236
|
+
### Common Issues
|
|
237
|
+
|
|
238
|
+
**Clients waiting (`cl_waiting > 0`)**:
|
|
239
|
+
1. Check for long-running transactions: `SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction';`
|
|
240
|
+
2. Increase `default_pool_size` (but diminishing returns beyond ~4x CPU cores)
|
|
241
|
+
3. Check if `query_wait_timeout` is being hit (errors in application logs)
|
|
242
|
+
|
|
243
|
+
**Server connections not being returned**:
|
|
244
|
+
1. `idle in transaction` sessions hold connections — set `idle_in_transaction_session_timeout` in PostgreSQL
|
|
245
|
+
2. Application not committing/rolling back — add explicit transaction management
|
|
246
|
+
|
|
247
|
+
## Application-Side Pooling
|
|
248
|
+
|
|
249
|
+
When PgBouncer isn't available, most drivers offer built-in connection pooling.
|
|
250
|
+
|
|
251
|
+
### Recommended Pool Sizes
|
|
252
|
+
|
|
253
|
+
**Per application instance**: 5-20 connections. Start low, increase only if you see connection wait times.
|
|
254
|
+
|
|
255
|
+
**Total across all instances**: Should not exceed ~4x database CPU cores for active connections.
|
|
256
|
+
|
|
257
|
+
### Common Driver Configuration
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
# Python (psycopg pool)
|
|
261
|
+
from psycopg_pool import ConnectionPool
|
|
262
|
+
|
|
263
|
+
pool = ConnectionPool(
|
|
264
|
+
conninfo="host=db port=5432 dbname=mydb",
|
|
265
|
+
min_size=5,
|
|
266
|
+
max_size=20,
|
|
267
|
+
max_idle=300, # close idle connections after 5 min
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
with pool.connection() as conn:
|
|
271
|
+
conn.execute("SELECT ...")
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// Node.js (pg)
|
|
276
|
+
const { Pool } = require('pg');
|
|
277
|
+
const pool = new Pool({
|
|
278
|
+
host: 'db',
|
|
279
|
+
database: 'mydb',
|
|
280
|
+
max: 20, // max connections in pool
|
|
281
|
+
idleTimeoutMillis: 30000,
|
|
282
|
+
connectionTimeoutMillis: 5000,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const result = await pool.query('SELECT ...');
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
```java
|
|
289
|
+
// Java (HikariCP)
|
|
290
|
+
HikariConfig config = new HikariConfig();
|
|
291
|
+
config.setJdbcUrl("jdbc:postgresql://db:5432/mydb");
|
|
292
|
+
config.setMaximumPoolSize(20);
|
|
293
|
+
config.setMinimumIdle(5);
|
|
294
|
+
config.setIdleTimeout(300000);
|
|
295
|
+
config.setConnectionTimeout(5000);
|
|
296
|
+
|
|
297
|
+
HikariDataSource ds = new HikariDataSource(config);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Application Pool + PgBouncer
|
|
301
|
+
|
|
302
|
+
You can stack both. Each application instance pools locally (5-10 connections), and PgBouncer pools across all instances:
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
App1 (pool: 10) ──┐
|
|
306
|
+
App2 (pool: 10) ──┼──→ PgBouncer (pool: 30) ──→ PostgreSQL
|
|
307
|
+
App3 (pool: 10) ──┘
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
Set application pool sizes low when using PgBouncer — the point is to reduce total connections, not add them up.
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Hot Standby & Read Replicas Reference
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Streaming replication overview
|
|
5
|
+
- Hot standby configuration
|
|
6
|
+
- Monitoring replication lag
|
|
7
|
+
- Replication conflicts
|
|
8
|
+
- Synchronous vs asynchronous replication
|
|
9
|
+
- Promoting a standby
|
|
10
|
+
|
|
11
|
+
## Streaming Replication Overview
|
|
12
|
+
|
|
13
|
+
Physical (streaming) replication creates an exact copy of the primary database on one or more standby servers. Unlike logical replication, it replicates the entire cluster (all databases, all objects) at the WAL level.
|
|
14
|
+
|
|
15
|
+
**Hot standby** allows read-only queries on the standby while it continuously replays WAL from the primary. This is the standard mechanism for PostgreSQL read replicas.
|
|
16
|
+
|
|
17
|
+
### Key Differences from Logical Replication
|
|
18
|
+
|
|
19
|
+
| Aspect | Physical (streaming) | Logical |
|
|
20
|
+
|--------|---------------------|---------|
|
|
21
|
+
| Scope | Entire cluster | Selected tables |
|
|
22
|
+
| PG versions | Must match major version | Can differ |
|
|
23
|
+
| Standby writable? | No (read-only) | Yes (for non-replicated tables) |
|
|
24
|
+
| DDL replicated? | Yes (via WAL) | No |
|
|
25
|
+
| Use case | HA, read replicas | CDC, selective sync, cross-version migration |
|
|
26
|
+
|
|
27
|
+
## Hot Standby Configuration
|
|
28
|
+
|
|
29
|
+
### On the Primary
|
|
30
|
+
|
|
31
|
+
```sql
|
|
32
|
+
-- Check current settings
|
|
33
|
+
SHOW wal_level; -- must be 'replica' or 'logical'
|
|
34
|
+
SHOW max_wal_senders; -- must have available sender slots
|
|
35
|
+
SHOW max_replication_slots; -- one per standby for slot-based replication
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Key settings (in `postgresql.conf`):
|
|
39
|
+
- `wal_level = replica` (default)
|
|
40
|
+
- `max_wal_senders = 10` (enough for all standbys)
|
|
41
|
+
- `max_replication_slots = 10` (optional but recommended — prevents WAL removal before standby catches up)
|
|
42
|
+
|
|
43
|
+
### On the Standby
|
|
44
|
+
|
|
45
|
+
Key settings:
|
|
46
|
+
- `hot_standby = on` (allows read queries during recovery — default)
|
|
47
|
+
- `primary_conninfo = 'host=primary_host user=repl_user ...'` (connection to primary)
|
|
48
|
+
- `primary_slot_name = 'standby_slot'` (optional — use a replication slot)
|
|
49
|
+
|
|
50
|
+
### Replication Slots (Recommended)
|
|
51
|
+
|
|
52
|
+
Slots prevent the primary from removing WAL segments before the standby has replayed them:
|
|
53
|
+
|
|
54
|
+
```sql
|
|
55
|
+
-- On the primary: create a physical replication slot
|
|
56
|
+
SELECT pg_create_physical_replication_slot('standby1_slot');
|
|
57
|
+
|
|
58
|
+
-- List slots
|
|
59
|
+
SELECT slot_name, slot_type, active, restart_lsn
|
|
60
|
+
FROM pg_replication_slots;
|
|
61
|
+
|
|
62
|
+
-- Drop a slot (if standby is permanently removed)
|
|
63
|
+
SELECT pg_drop_replication_slot('standby1_slot');
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Warning**: An inactive slot causes WAL to accumulate indefinitely on the primary, potentially filling the disk.
|
|
67
|
+
|
|
68
|
+
## Monitoring Replication Lag
|
|
69
|
+
|
|
70
|
+
### On the Primary: pg_stat_replication
|
|
71
|
+
|
|
72
|
+
```sql
|
|
73
|
+
SELECT
|
|
74
|
+
pid,
|
|
75
|
+
application_name,
|
|
76
|
+
client_addr,
|
|
77
|
+
state,
|
|
78
|
+
sent_lsn,
|
|
79
|
+
write_lsn,
|
|
80
|
+
flush_lsn,
|
|
81
|
+
replay_lsn,
|
|
82
|
+
pg_size_pretty(pg_wal_lsn_diff(sent_lsn, replay_lsn)) AS replay_lag,
|
|
83
|
+
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)) AS send_lag,
|
|
84
|
+
write_lag,
|
|
85
|
+
flush_lag,
|
|
86
|
+
replay_lag AS replay_lag_time
|
|
87
|
+
FROM pg_stat_replication;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**LSN progression**: `pg_current_wal_lsn()` → `sent_lsn` → `write_lsn` → `flush_lsn` → `replay_lsn`. The gap between any two is a measure of lag at that stage.
|
|
91
|
+
|
|
92
|
+
### On the Standby: pg_stat_wal_receiver
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
SELECT
|
|
96
|
+
status,
|
|
97
|
+
written_lsn,
|
|
98
|
+
flushed_lsn,
|
|
99
|
+
latest_end_lsn,
|
|
100
|
+
latest_end_time,
|
|
101
|
+
slot_name,
|
|
102
|
+
conninfo
|
|
103
|
+
FROM pg_stat_wal_receiver;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### On the Standby: Lag in Seconds
|
|
107
|
+
|
|
108
|
+
```sql
|
|
109
|
+
-- How far behind is the standby?
|
|
110
|
+
SELECT
|
|
111
|
+
now() - pg_last_xact_replay_timestamp() AS replay_lag,
|
|
112
|
+
pg_last_wal_receive_lsn() AS received_lsn,
|
|
113
|
+
pg_last_wal_replay_lsn() AS replayed_lsn,
|
|
114
|
+
pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) AS replay_lag_bytes;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Caveat**: `pg_last_xact_replay_timestamp()` only updates when transactions are replayed. On an idle primary, it may show a large lag even though the standby is fully caught up. Check `received_lsn = replayed_lsn` for actual status.
|
|
118
|
+
|
|
119
|
+
### Is the Standby in Recovery?
|
|
120
|
+
|
|
121
|
+
```sql
|
|
122
|
+
-- Returns true on a standby, false on a primary
|
|
123
|
+
SELECT pg_is_in_recovery();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Replication Conflicts
|
|
127
|
+
|
|
128
|
+
On a hot standby, long-running read queries can conflict with WAL replay. When replay needs to apply changes that conflict with an active query (e.g., dropping a table, vacuuming rows the query is reading), PostgreSQL must choose: wait for the query or cancel it.
|
|
129
|
+
|
|
130
|
+
### max_standby_streaming_delay
|
|
131
|
+
|
|
132
|
+
Controls how long the standby waits for conflicting queries before cancelling them:
|
|
133
|
+
|
|
134
|
+
```sql
|
|
135
|
+
SHOW max_standby_streaming_delay; -- default: 30s
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- `30s` (default): Standby waits up to 30 seconds, then cancels conflicting queries
|
|
139
|
+
- `-1`: Wait forever (replay pauses until the query finishes — can cause unbounded lag)
|
|
140
|
+
- `0`: Cancel conflicting queries immediately (minimal lag, but queries may fail)
|
|
141
|
+
|
|
142
|
+
### max_standby_archive_delay
|
|
143
|
+
|
|
144
|
+
Same concept but for WAL segments being replayed from archive (rather than streaming):
|
|
145
|
+
|
|
146
|
+
```sql
|
|
147
|
+
SHOW max_standby_archive_delay; -- default: 30s
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### The Common Error
|
|
151
|
+
|
|
152
|
+
When a query on the standby is cancelled due to a conflict:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
ERROR: canceling statement due to conflict with recovery
|
|
156
|
+
DETAIL: User was holding shared buffer pin for too long.
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Solutions (in order of preference):**
|
|
160
|
+
1. Keep queries on the standby short
|
|
161
|
+
2. Increase `max_standby_streaming_delay` (trades lag for query stability)
|
|
162
|
+
3. Enable `hot_standby_feedback` (see below)
|
|
163
|
+
4. Use a logical replica instead of hot standby for long-running analytics
|
|
164
|
+
|
|
165
|
+
### hot_standby_feedback
|
|
166
|
+
|
|
167
|
+
When enabled, the standby informs the primary about which rows it still needs, preventing the primary's VACUUM from removing them:
|
|
168
|
+
|
|
169
|
+
```sql
|
|
170
|
+
SHOW hot_standby_feedback; -- default: off
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
**Pros**: Eliminates most replication conflicts — long queries on the standby won't be cancelled.
|
|
174
|
+
|
|
175
|
+
**Cons**: Can cause table bloat on the primary because VACUUM can't remove dead rows that the standby still references.
|
|
176
|
+
|
|
177
|
+
**Recommendation**: Enable only if you have long-running analytical queries on the standby and can tolerate some extra bloat on the primary.
|
|
178
|
+
|
|
179
|
+
## Synchronous vs Asynchronous Replication
|
|
180
|
+
|
|
181
|
+
### Asynchronous (Default)
|
|
182
|
+
|
|
183
|
+
The primary doesn't wait for standby acknowledgment before committing. Fastest, but a primary failure can lose recently committed transactions not yet replicated.
|
|
184
|
+
|
|
185
|
+
### Synchronous
|
|
186
|
+
|
|
187
|
+
The primary waits for at least one standby to confirm before returning commit success:
|
|
188
|
+
|
|
189
|
+
```sql
|
|
190
|
+
-- On the primary
|
|
191
|
+
SHOW synchronous_standby_names; -- e.g., 'standby1'
|
|
192
|
+
SHOW synchronous_commit; -- 'on', 'remote_write', 'remote_apply', etc.
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Synchronous commit levels:
|
|
196
|
+
|
|
197
|
+
| Level | Primary waits for | Durability | Latency impact |
|
|
198
|
+
|-------|-------------------|------------|----------------|
|
|
199
|
+
| `on` (default with sync standbys) | Standby WAL flush | Strong | Moderate |
|
|
200
|
+
| `remote_write` | Standby WAL write (not fsync) | Good | Lower |
|
|
201
|
+
| `remote_apply` | Standby WAL replay | Strongest (read-your-writes on standby) | Highest |
|
|
202
|
+
| `local` | Local WAL flush only | Primary only | None |
|
|
203
|
+
| `off` | Nothing | Weakest | None |
|
|
204
|
+
|
|
205
|
+
## Promoting a Standby
|
|
206
|
+
|
|
207
|
+
To promote a standby to become the new primary (failover):
|
|
208
|
+
|
|
209
|
+
```sql
|
|
210
|
+
-- On the standby:
|
|
211
|
+
SELECT pg_promote();
|
|
212
|
+
|
|
213
|
+
-- Or from the command line:
|
|
214
|
+
-- pg_ctl promote -D /path/to/data
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
After promotion:
|
|
218
|
+
- The standby stops replay and opens for writes
|
|
219
|
+
- Applications must be redirected to the new primary
|
|
220
|
+
- Other standbys must be reconfigured to follow the new primary
|
|
221
|
+
- The old primary must not be restarted without reconfiguring (risk of split-brain)
|