-
-
Notifications
You must be signed in to change notification settings - Fork 129
fix(db): reclaim Capgo-EU swap pressure without upgrading #2721
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
31fe40b
c63d4db
ad18df6
0347360
d731d6d
169b939
8b41f3f
0e2bbe1
03ed950
1ef934d
dd9b96a
140138f
f537d99
a3b7649
6a6fd8a
4757e8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| -- Capgo-EU Phase A reclaim (run manually in a maintenance window). | ||
|
riderx marked this conversation as resolved.
riderx marked this conversation as resolved.
riderx marked this conversation as resolved.
riderx marked this conversation as resolved.
riderx marked this conversation as resolved.
riderx marked this conversation as resolved.
|
||
| -- REQUIRED: psql (uses \gexec; VACUUM cannot run inside a transaction). | ||
| -- Prefer ~/.pgpass / PGPASSFILE instead of putting the password on the CLI. | ||
| -- Example: | ||
| -- psql "postgresql://postgres@HOST:5432/postgres?sslmode=require" -v ON_ERROR_STOP=1 -f scripts/ops/reclaim_supabase_swap.sql | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| -- Safe order: index -> truncate -> archives -> null manifests -> audit trim. | ||
| -- Re-run the FULL script until cleanup notices report deleted/updated = 0 | ||
| -- (functions always emit a notice, including zero totals). | ||
|
|
||
| SET lock_timeout = '5s'; | ||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 0) Baseline sizes | ||
| -- --------------------------------------------------------------------------- | ||
| SELECT pg_size_pretty(pg_database_size(current_database())::bigint) AS db_size; | ||
|
|
||
| SELECT | ||
| relname, | ||
| n_live_tup, | ||
| pg_size_pretty(pg_total_relation_size(format('%I.%I', schemaname, relname)::regclass)::bigint) AS total | ||
| FROM pg_stat_user_tables | ||
| WHERE (schemaname, relname) IN ( | ||
| ('net', '_http_response'), | ||
| ('public', 'audit_logs'), | ||
| ('public', 'app_versions'), | ||
| ('public', 'manifest'), | ||
| ('pgmq', 'a_on_version_update'), | ||
| ('pgmq', 'a_on_manifest_create'), | ||
| ('pgmq', 'a_webhook_dispatcher'), | ||
| ('pgmq', 'a_on_channel_update') | ||
| ) | ||
| ORDER BY pg_total_relation_size(format('%I.%I', schemaname, relname)::regclass) DESC; | ||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 0b) Candidate index for hourly nulling (non-blocking; must be outside a tx) | ||
| -- --------------------------------------------------------------------------- | ||
| CREATE INDEX CONCURRENTLY IF NOT EXISTS app_versions_manifest_present_idx | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: A lock timeout or interrupted concurrent build leaves an invalid index that every instructed rerun skips because of Prompt for AI agents |
||
| ON public.app_versions USING btree (id) | ||
| WHERE manifest IS NOT NULL; | ||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 1) Truncate pg_net response bloat | ||
| -- --------------------------------------------------------------------------- | ||
| TRUNCATE TABLE net._http_response; | ||
|
riderx marked this conversation as resolved.
|
||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 2) Purge pgmq archives/stuck messages. | ||
| -- Re-run the FULL script until archived_deleted=0 and stuck_deleted=0. | ||
| -- --------------------------------------------------------------------------- | ||
| SELECT public.cleanup_queue_messages(); | ||
|
riderx marked this conversation as resolved.
|
||
|
|
||
| -- Vacuum Capgo-EU evidenced bloated queues only. | ||
| VACUUM (VERBOSE) pgmq.a_on_version_update; | ||
| VACUUM (VERBOSE) pgmq.a_on_manifest_create; | ||
| VACUUM (VERBOSE) pgmq.a_webhook_dispatcher; | ||
| VACUUM (VERBOSE) pgmq.a_on_channel_update; | ||
| VACUUM (VERBOSE) pgmq.q_on_version_update; | ||
| VACUUM (VERBOSE) pgmq.q_on_manifest_create; | ||
| VACUUM (VERBOSE) pgmq.q_webhook_dispatcher; | ||
| VACUUM (VERBOSE) pgmq.q_on_channel_update; | ||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 3) Null fully migrated app_versions.manifest arrays (s3_path + file_hash). | ||
| -- Re-run the FULL script until updated=0. | ||
| -- --------------------------------------------------------------------------- | ||
| SELECT public.null_migrated_app_version_manifests(); | ||
|
|
||
| VACUUM (ANALYZE, VERBOSE) public.app_versions; | ||
| -- Optional TOAST compaction after updated=0: | ||
| -- VACUUM (FULL, VERBOSE) public.app_versions; | ||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 4) Trim audit_logs older than 30 days. | ||
| -- Re-run the FULL script until deleted=0. | ||
| -- --------------------------------------------------------------------------- | ||
| SELECT public.cleanup_old_audit_logs(); | ||
|
|
||
| VACUUM (ANALYZE, VERBOSE) public.audit_logs; | ||
| -- Optional TOAST compaction after deleted=0: | ||
| -- VACUUM (FULL, VERBOSE) public.audit_logs; | ||
|
|
||
| -- --------------------------------------------------------------------------- | ||
| -- 5) Final sizes | ||
| -- --------------------------------------------------------------------------- | ||
| SELECT pg_size_pretty(pg_database_size(current_database())::bigint) AS db_size_after; | ||
|
|
||
| SELECT | ||
| relname, | ||
| n_live_tup, | ||
| pg_size_pretty(pg_total_relation_size(format('%I.%I', schemaname, relname)::regclass)::bigint) AS total | ||
| FROM pg_stat_user_tables | ||
| WHERE (schemaname, relname) IN ( | ||
| ('net', '_http_response'), | ||
| ('public', 'audit_logs'), | ||
| ('public', 'app_versions'), | ||
| ('public', 'manifest'), | ||
| ('pgmq', 'a_on_version_update'), | ||
| ('pgmq', 'a_on_manifest_create'), | ||
| ('pgmq', 'a_webhook_dispatcher'), | ||
| ('pgmq', 'a_on_channel_update') | ||
| ) | ||
| ORDER BY pg_total_relation_size(format('%I.%I', schemaname, relname)::regclass) DESC; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| -- Post-deploy / post-reclaim verification for Capgo-EU swap pressure. | ||
|
riderx marked this conversation as resolved.
|
||
| -- REQUIRED: psql (uses \gexec). Example: | ||
| -- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f scripts/ops/verify_supabase_swap.sql | ||
|
|
||
| SELECT pg_size_pretty(pg_database_size(current_database())::bigint) AS db_size; | ||
|
|
||
| SELECT | ||
| name, | ||
| setting, | ||
| unit | ||
| FROM pg_settings | ||
| WHERE name IN ('shared_buffers', 'work_mem', 'max_connections'); | ||
|
|
||
| SELECT | ||
| relname, | ||
| n_live_tup, | ||
| pg_size_pretty(pg_total_relation_size(format('%I.%I', schemaname, relname)::regclass)::bigint) AS total | ||
| FROM pg_stat_user_tables | ||
| WHERE (schemaname, relname) IN ( | ||
| ('net', '_http_response'), | ||
| ('public', 'audit_logs'), | ||
| ('public', 'app_versions'), | ||
| ('public', 'manifest'), | ||
| ('pgmq', 'a_on_version_update'), | ||
| ('pgmq', 'a_on_manifest_create'), | ||
| ('pgmq', 'a_webhook_dispatcher'), | ||
| ('pgmq', 'a_on_channel_update') | ||
| ) | ||
| ORDER BY pg_total_relation_size(format('%I.%I', schemaname, relname)::regclass) DESC; | ||
|
|
||
| -- Sample first 1000 non-null manifests; a zero does not prove global completion. | ||
| SELECT count(*) AS eligible_dual_storage_sample | ||
| FROM ( | ||
| SELECT sample.id | ||
| FROM ( | ||
| SELECT av.id, av.manifest | ||
| FROM public.app_versions AS av | ||
| WHERE av.manifest IS NOT NULL | ||
| ORDER BY av.id | ||
| LIMIT 1000 | ||
|
riderx marked this conversation as resolved.
|
||
| ) AS sample | ||
| WHERE NOT EXISTS ( | ||
| SELECT 1 | ||
| FROM unnest(sample.manifest) AS entry(file_name, s3_path, file_hash) | ||
|
riderx marked this conversation as resolved.
|
||
| WHERE NOT EXISTS ( | ||
| SELECT 1 | ||
| FROM public.manifest AS m | ||
| WHERE m.app_version_id = sample.id | ||
| AND m.s3_path = entry.s3_path | ||
| AND m.file_hash = entry.file_hash | ||
| ) | ||
| ) | ||
| ) AS eligible; | ||
|
|
||
| SELECT | ||
| name, | ||
| enabled, | ||
| hour_interval, | ||
| run_at_hour, | ||
| run_at_minute, | ||
| target, | ||
| description, | ||
| updated_at | ||
| FROM public.cron_tasks | ||
| WHERE name IN ( | ||
| 'cleanup_queue_messages', | ||
| 'cleanup_net_http_response', | ||
| 'cleanup_old_audit_logs', | ||
| 'null_migrated_app_version_manifests' | ||
| ) | ||
| ORDER BY name; | ||
|
|
||
| SELECT indexname | ||
|
riderx marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: An interrupted concurrent build can appear here by name while remaining INVALID, leaving hourly manifest cleanup without the intended index and preventing (Based on your team's feedback about building the manifest index concurrently.) Prompt for AI agents |
||
| FROM pg_indexes | ||
| WHERE schemaname = 'public' | ||
| AND indexname = 'app_versions_manifest_present_idx'; | ||
|
|
||
| SELECT EXISTS ( | ||
| SELECT 1 | ||
| FROM public.audit_logs | ||
| WHERE created_at < now() - interval '30 days' | ||
| LIMIT 1 | ||
| ) AS has_audit_logs_older_than_30d; | ||
|
|
||
| SELECT format( | ||
| $fmt$SELECT %L AS queue_name, | ||
| EXISTS ( | ||
| SELECT 1 | ||
| FROM pgmq.%I | ||
| WHERE archived_at < now() - interval '2 days' | ||
| LIMIT 1 | ||
| ) AS has_rows_older_than_2d;$fmt$, | ||
| queue_name, | ||
| 'a_' || pg_catalog.lower(queue_name) | ||
| ) | ||
| FROM pgmq.list_queues() | ||
| \gexec | ||
|
|
||
| SELECT format( | ||
| $fmt$SELECT %L AS queue_name, | ||
| EXISTS ( | ||
| SELECT 1 | ||
| FROM pgmq.%I | ||
| WHERE read_ct > 5 | ||
| LIMIT 1 | ||
| ) AS has_stuck_read_ct_gt_5;$fmt$, | ||
| queue_name, | ||
| 'q_' || pg_catalog.lower(queue_name) | ||
| ) | ||
| FROM pgmq.list_queues() | ||
| \gexec | ||
|
|
||
| SELECT | ||
| 'index hit rate' AS name, | ||
| ROUND((sum(idx_blks_hit)::numeric / nullif(sum(idx_blks_hit + idx_blks_read), 0) * 100), 2) AS ratio | ||
| FROM pg_statio_user_indexes | ||
| UNION ALL | ||
| SELECT | ||
| 'table hit rate', | ||
| ROUND((sum(heap_blks_hit)::numeric / nullif(sum(heap_blks_hit) + sum(heap_blks_read), 0) * 100), 2) | ||
| FROM pg_statio_user_tables; | ||
Uh oh!
There was an error while loading. Please reload this page.