Skip to content

feat(devbox): add devbox.onEvict eviction notifications (SSE)#820

Open
jrvb-rl wants to merge 4 commits into
release-please--branches--main--changes--next--components--api-clientfrom
feat/devbox-on-evict-sse
Open

feat(devbox): add devbox.onEvict eviction notifications (SSE)#820
jrvb-rl wants to merge 4 commits into
release-please--branches--main--changes--next--components--api-clientfrom
feat/devbox-on-evict-sse

Conversation

@jrvb-rl

@jrvb-rl jrvb-rl commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Description

Follow-on to the server-side flex eviction-notification work (monorepo #10325 and its successor SSE endpoint). Adds the object-oriented client surface for eviction notifications.

New API: devbox.onEvict(callback) (and devbox.cancelOnEvict()) on the Devbox wrapper.

How it works (internal state management):

  • A per-client EvictionMonitor (src/sdk/eviction.ts) holds the interest set: Map<devbox_id, callback>. Monitors are looked up via a WeakMap<Runloop, EvictionMonitor> (getEvictionMonitor), so every Devbox built from the same generated client shares one monitor and thus one SSE connection. No Devbox/factory signatures changed.
  • The first onEvict across any devbox opens a single account-wide devboxes.watchEvictions() SSE stream via a background for await loop.
  • On each event: the id is matched against the interest set; unknown ids are discarded. The devbox is removed before its callback runs, so it fires at most once even if the server repeats a notification.
  • When the interest set empties, the stream's AbortController is aborted and the stream closed. Re-registering re-opens it.
  • The server replays all currently-pending evictions on connect, so late registrants are still notified.

Dependency / status

⚠️ Draft. This depends on the Stainless-generated devboxes.watchEvictions method and the DevboxEvictionEvent type (devbox_id, eviction_deadline_ms), which are generated downstream once the server endpoint lands. Those symbols are imported by assumed name from ../resources/devboxes/devboxes and will be reconciled once generation lands. No generated code was modified.

Note: jest.config.objects.js enforces 100% function coverage over src/sdk, so the object-oriented smoke test for onEvict/cancelOnEvict (plus a mocked tests/objects unit test) is required and will be added when the endpoint is available to exercise.

Testing

Deferred until the generated endpoint exists (see above).

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

❌ Object Smoke Tests Failed

Test Results

❌ Some smoke tests failed

Please fix the failing tests before checking coverage.

📋 View full test logs

@reflex-loop

reflex-loop Bot commented Jul 23, 2026

Copy link
Copy Markdown

Reflex agent status: Completed

The agent completed its work.

This PR was created by Reflex.

View the agent run →

This comment updates in place as the agent works.

@jrvb-rl

jrvb-rl commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Reconciled with the endpoint as landed:

  • callback is now callback(devbox, evictionDeadlineMs) (the Devbox object + Unix-ms deadline)
  • uses the real generated type DevboxEvictionEventView

Ordering: depends on runloopai/runloop#10404, which marks watch_evictions as streaming in openapi.stainless.yml so Stainless generates devboxes.watchEvictions() -> Stream<DevboxEvictionEventView>. Once that merges and Stainless regenerates (the .stats.yml bump lands the method + type), this rebases green.

claude added 2 commits July 24, 2026 09:34
Adds an object-oriented `Devbox.onEvict(callback)` backed by a per-client
`EvictionMonitor`. The first registration opens a single account-wide
`watchEvictions` SSE stream; incoming notifications are matched against the local
interest set, the devbox is removed before its callback fires (at-most-once), and
the stream is closed once the interest set empties.

Depends on the Stainless-generated `devboxes.watchEvictions` method and
`DevboxEvictionEvent` type, which land downstream once the server endpoint merges.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Use the real generated event type DevboxEvictionEventView (the endpoint's view)
  in place of the assumed DevboxEvictionEvent.
- Invoke the callback as callback(devbox, evictionDeadlineMs): the Devbox object
  and the Unix millisecond deadline, instead of passing the raw event.

Requires the main-repo stainless config change that generates watchEvictions as
Stream<DevboxEvictionEventView> (runloopai/runloop#10404).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jrvb-rl
jrvb-rl force-pushed the feat/devbox-on-evict-sse branch from c5c33b0 to d8d6f4c Compare July 24, 2026 09:34
@jrvb-rl
jrvb-rl changed the base branch from main to release-please--branches--main--changes--next--components--api-client July 24, 2026 09:34
@jrvb-rl
jrvb-rl marked this pull request as ready for review July 24, 2026 10:04
@jrvb-rl
jrvb-rl requested review from james-rl and sid-rl July 24, 2026 10:04
Reflex and others added 2 commits July 24, 2026 10:10
Hermetic object-coverage test driving the shared EvictionMonitor via an in-memory
fake watch_evictions stream: asserts onEvict fires once with (devbox, deadline),
unmatched devbox ids are discarded, and cancelOnEvict aborts the stream. Gives the
object-coverage suite 100% function coverage of the eviction wrapper without a live
eviction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mux SSE route moved from /v1/devboxes/watch_evictions to
/v1/devboxes/evictions/watch (runloopai/runloop#10409) to avoid colliding
with GET /v1/devboxes/{id}. Update the generated request path so the
watchEvictions method reaches the new endpoint. Method surface unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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