fix(sandbox): fit the nightly cleanup inside PostgREST's 8s session cap (#1451)
* fix(sandbox): fit the nightly cleanup inside PostgREST's 8s session cap Follow-up to #1449. Profiling the repaired teardown on prod puts one sandbox user at ~3s (the auth.users delete fans out over ~250 FK triggers; FK indexes were tried inside an aborted transaction and do not help), while every PostgREST session inherits authenticator's statement_timeout = 8s. The nightly RPC call therefore times out and ROLLS BACK wholesale: a second silent-failure mode for the same cron. - cleanup_expired_sandbox_users gets a function-local statement_timeout of 290s (same sanctioned pattern as undo_sie_import, 20260702154500) via migration 20260807150000. - The cron route bounds each night to 60 users (~180s), exports maxDuration = 300, and the backlog drains over a few nights. - Tests: route asserts the bounded rpc call and the maxDuration budget; the pg suite pins proconfig containing statement_timeout=290s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(db): index journal_entry_lines.account_id (chart-account cascade seq-scans 730k rows) Caught live during the backlog purge: DELETE FROM auth.users cascades chart_of_accounts deletion, whose ON DELETE SET NULL fires an unindexed UPDATE over journal_entry_lines per account (~37 per sandbox company). This is the bulk of the ~3s per-user teardown cost. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
7411a0171b
commit
bd7a423b86
@@ -352,6 +352,21 @@ describe('sandbox cleanup RPCs (pg)', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('cleanup_expired_sandbox_users carries its own statement_timeout', async () => {
|
||||
// PostgREST sessions inherit authenticator's 8s statement_timeout while
|
||||
// one sandbox teardown costs ~3s, so without a function-local override
|
||||
// the nightly batch times out and rolls back wholesale (migration
|
||||
// 20260807150000, same pattern as undo_sie_import).
|
||||
const { rows } = await getPool().query<{ proconfig: string[] | null }>(
|
||||
`SELECT p.proconfig
|
||||
FROM pg_proc p
|
||||
JOIN pg_namespace n ON n.oid = p.pronamespace
|
||||
WHERE n.nspname = 'public' AND p.proname = 'cleanup_expired_sandbox_users'`,
|
||||
)
|
||||
expect(rows).toHaveLength(1)
|
||||
expect(rows[0]!.proconfig ?? []).toContain('statement_timeout=290s')
|
||||
})
|
||||
|
||||
it('is executable by service_role only', async () => {
|
||||
const { rows } = await getPool().query<{
|
||||
svc_user: boolean
|
||||
|
||||
Reference in New Issue
Block a user