Skip to content

Add bounded scale-to-zero leases - #366

Open
tnsardesai wants to merge 5 commits into
mainfrom
hypeship/lease-scale-to-zero-pin
Open

Add bounded scale-to-zero leases#366
tnsardesai wants to merge 5 commits into
mainfrom
hypeship/lease-scale-to-zero-pin

Conversation

@tnsardesai

@tnsardesai tnsardesai commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

problem

A handler that streams a large response can finish once the final bytes are accepted by the guest TCP send buffer, before those bytes have reached metro-api. Releasing the request-scoped scale-to-zero hold at that point can suspend the VM with response bytes still queued.

Metro-api needs a crash-safe way to hold scale-to-zero disabled until the guest response has been fully read. The existing disable/enable pin is intentionally a permanent boolean used by lifecycle management, so reusing it for individual responses would let one response release another caller's pin and could leave a VM pinned forever if metro-api exits.

change

  • add additive PUT/DELETE /scaletozero/leases/{lease_id} endpoints
  • keep named leases independent from the existing permanent pin and request refcount
  • renew a repeated lease ID idempotently
  • expire leases automatically after a caller-supplied TTL, capped at five minutes by the API, with a safe default scheduler for directly constructed controllers
  • cap each guest at 1,024 concurrent leases and return a distinct 409 conflict at the limit
  • log background re-enable failures and keep explicit release retries effective
  • re-enable scale-to-zero only after the request refcount, permanent pin, and all bounded leases are gone
  • regenerate the OpenAPI server/client and telemetry operation map

Existing /scaletozero/disable and /scaletozero/enable behavior is unchanged.

tests

  • make oapi-generate
  • go build ./...
  • go vet ./...
  • go test -race ./lib/scaletozero ./cmd/api/api
  • go test ./lib/scaletozero -run '^TestDebouncedControllerLeaseRenewalSurvivesStaleExpiry$' -count=50
  • go test ./lib/scaletozero -run '^TestDebouncedControllerLeaseDefaultsExpiryScheduler$' -count=50
  • go test -race $(go list ./... | grep -v '/e2e$') (all changed packages passed; one unrelated lib/devtoolsproxy Chromium temp-directory cleanup raced once)
  • go test -race ./lib/devtoolsproxy (retry passed)

rollout

Release this in browser images before relying on bounded leases from metro-api. The metro-api change treats a 404/405 as an older image and retains its independent stall-wake watchdog during the image rollout.


Note

Medium Risk
Changes when VMs can scale to zero (infrastructure lifecycle) but the API is additive, TTL-bounded, and existing disable/enable pin behavior is unchanged.

Overview
Adds bounded scale-to-zero leases so callers (e.g. metro-api) can keep a VM awake for a limited time after a streaming response ends, without using the permanent pin or request refcount.

New PUT / DELETE /scaletozero/leases/{lease_id} endpoints validate lease IDs and ttl_seconds (1–300), delegate to AcquireLease / ReleaseLease on the existing scale-to-zero controller, and map lease-cap exhaustion to 409. OpenAPI client/server and telemetry operation categories are regenerated.

DebouncedController now tracks named leases with timers (renew on repeat ID), a 1024-lease cap, and treats active leases like pins/refcounts when deciding re-enable; cooldown re-enable failures are logged instead of silently ignored.

Reviewed by Cursor Bugbot for commit 8d0b726. Bugbot is set up for automated code reviews on this repo. Configure here.

@tnsardesai
tnsardesai marked this pull request as ready for review September 3, 2026 22:21

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ce21b43. Configure here.

Comment thread server/openapi.yaml Outdated

@sjmiller609 sjmiller609 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • server/lib/scaletozero/scaletozero.go:71-75 — Considering returning an error if called in Hypeman instead of succeeding.
  • server/openapi.yaml:1647-1698 — consider if we should delete the "release" endpoint, since we could just renew the lease with a shorter duration? Seems subjective though, so whatever you prefer is good (e.g. just set TTL to 1s or 0s versus DELETE)
  • note: I checked on the clock jumping concern and I think there isn't one because this uses relative monotonic timing

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