Repository navigation
SpawnClient: observe-only monitor loop on every non-mock provider (#126) - #132
Merged
Merged
Conversation
The monitor loop ran the lifecycle engine against EC2 with isIdle: true hardcoded and the launch time as last activity, so an open portal tab stopped every spawn-managed instance older than its spawn:idle-timeout, busy or not, and terminated on TTL/cost behind spored and the reaper. New ClientOptions.lifecycle: "observe" (refresh, warnings, fan-out progress; never a lifecycle action) is the default for every provider but a MockProvider; "simulate" keeps the engine for the mock demo and throws on anything else. setProvider re-derives the mode. Fixes #126
Keeps the barrel's client export block untouched, so this PR and the Refs #126
scttfrdmn
force-pushed
the
fix/126-viewer-mode
branch
from
November 11, 2026 05:06
5145e81 to
815a7f5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #126
Problem
SpawnClient.tick()ran spored's lifecycle engine against real EC2 withisIdle: truehardcoded, and EC2Provider setslastActivityMsto the launch time. So any open portal tab calledStopInstanceson every spawn-managed instance older than itsspawn:idle-timeout, however busy it was. A Gospawn launchwithout--ttldefaults to a 1h idle timeout, so a CLI job was stopped one hour after launch. The same loop also terminated on TTL and cost limit, duplicating spored and the reaper.Change
New
ClientOptions.lifecycle: "observe" | "simulate":"observe"is the default for every provider except aMockProvider. That includes EC2 and substrate, because non-billable is not the same as simulated. The loop refreshes, emits TTL and cost warnings once each, and advances the sweeps, queues and job arrays this client started. It never takes a lifecycle action. It evaluates idle as not idle, because the browser can't see activity on the box."simulate"keeps the engine for the mock demo, where the sim clock is the activity signal. Passing it with a non-mock provider throws.client.lifecycleModereports which mode applies.setProviderre-derives it, so a mock client switched to EC2 becomes a viewer.There is deliberately no mode that enforces against EC2.
Tests (
src/core/client.viewer.test.ts)The client is built exactly as the portal will build it:
new SpawnClient({ provider: new EC2Provider({...}) }), with no lifecycle option and no endpoint, soisRealis true. It runs against a fake EC2 (EC2Client.prototype.sendstubbed, no network). The fleet has every rule already due: a CLI job past its idle timeout (the audit's case), a past-TTL instance, an over-budget instance, and an on-complete hibernate-on-idle instance.startMonitorticks under fake timers send at least 40DescribeInstancesand zero other commands, with noactionevents.step(), over a substrate endpoint, and aftersetProvider(mock → EC2).lifecycle: "observe"makes it a viewer.I checked the guard: when the observe branch is forced off, 5 of these tests fail.
Breaking for existing consumers?
Behaviour change, noted in the CHANGELOG. A caller that relied on the loop enforcing TTL, cost or idle on EC2 no longer gets that from spawn-ts. spored and the reaper enforce them, as they always did. There is no API removal.
Not in this PR
signalCompleteon a real provider is tracked in Dashboard card actions target the instance by Name (hits a terminated or other user's same-named instance) and cards re-render every ~125 ms so clicks are lost #128.void this.tick()) are tracked in Dashboard instance actions swallow errors: stop/start/extend/terminate fail silently #125.Also in this PR
src/aws/ec2.integration.test.ts(live-smoke, against substrate): this test asserted that the monitor terminated an expired-TTL instance over the wire. It now asserts the opposite, observe-only, and cleans up after itself.Merging alongside #133 / #134 / #135
There are no code conflicts. I trial-merged this PR into the tip of the #135 stack, and all 888 tests pass on the combined code. The only conflict is
CHANGELOG.md, because every PR replacesNothing yet.under Unreleased. Resolve it by keeping both entries.