Skip to content

Stop the lease-expiry cron from pinning Neon compute at 100% - #112

Merged
Barneyjm merged 1 commit into
mainfrom
claude/suboptimal-performance-qmf66l
Aug 17, 2026
Merged

Stop the lease-expiry cron from pinning Neon compute at 100%#112
Barneyjm merged 1 commit into
mainfrom
claude/suboptimal-performance-qmf66l

Conversation

@Barneyjm

Copy link
Copy Markdown
Owner

Problem

The Neon "100% compute used / at risk of suspension" alert isn't slow queries or user traffic — it's the lease-expiry cron cadence fighting Neon's autosuspend.

wrangler.toml ran the sweep on */5 * * * * — a DB query every 5 minutes, 24/7. Neon's serverless compute autosuspends after ~5 minutes of inactivity, so a query on exactly that interval means the compute never scales to zero. It runs continuously:

  • ~0.25 CU × 24h × 30d ≈ 180 CU-hours/month against a 100 CU-hour allowance → usage pinned at 100%.

Fix

Move the sweep to hourly (0 * * * *). Safe because the cron is only a backstop:

  • checkoutTask and listOpenTasks already reclaim lapsed locks lazily (reclaimLapsedLocks) on the hot path, so any active use of the pool self-heals a stranded reservation within a single request.
  • The cron only does anything when the system is fully idle — precisely when we want the compute suspended.

Idle periods now let Neon autosuspend (cron wake time drops from ~24h/day to ~2h/day, well under the allowance with headroom for real traffic). The only tradeoff: in a fully idle system, a crashed runner's budget reservation frees up in up to ~1h instead of ~5m. The 10-minute lease itself is unchanged, and the moment anyone touches the pool it's reclaimed immediately.

Changes

  • wrangler.toml — cron */5 * * * *0 * * * *, with a comment explaining the autosuspend interaction.
  • src/worker.ts / src/operations.ts — updated the "every 5 minutes" / "5-minute cron sweep" comments to match.

Verification

  • npm run typecheck — pass
  • npm run lint — pass
  • Full vitest suite not run here: this environment has no Postgres on localhost:5433 (the suite truncates tables and requires a local DB). No runtime logic changed and no test references the cron schedule, so nothing in the suite exercises this change.

Note for reviewer

This assumes Neon's autosuspend is at its default (~300s idle). If that window has been raised, the cron cadence should be retuned so the two don't fight.

🤖 Generated with Claude Code


Generated by Claude Code

The `*/5 * * * *` sweep ran expire() every 5 minutes, 24/7. Neon's
serverless compute autosuspends after ~5 minutes idle, so a query on that
exact cadence never let it scale to zero: the compute ran continuously
(~0.25 CU x 24h x 30d ~= 180 CU-hours/month), blowing past the 100 CU-hour
monthly allowance and pinning usage at 100%.

The sweep is only a backstop. checkoutTask and listOpenTasks already
reclaim lapsed locks lazily on the hot path (reclaimLapsedLocks), so any
active use of the pool self-heals a stranded reservation within one
request. The cron only does anything when the system is otherwise idle --
which is precisely when we want the compute suspended.

Move the backstop to hourly (`0 * * * *`). Idle periods now let Neon
autosuspend; the only cost is that a crashed runner's budget reservation in
a fully idle system lingers up to ~1h instead of ~5m (the 10-minute lease
itself is unchanged). Comments in wrangler.toml, worker.ts, and
operations.ts updated to match.

Co-Authored-By: Claude <noreply@anthropic.com>
@Barneyjm
Barneyjm merged commit 9be02d1 into main Aug 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants