Add a start/stop controller for the S2 storage sink - #401
Open
archandatta wants to merge 7 commits into
Open
archandatta wants to merge 7 commits into
archandatta wants to merge 7 commits into
Conversation
The writer is opened at boot today, which leaves no way to decide per session whether events are persisted at all. Wrap it in a controller that resolves the stream lazily and opens at most one writer, so a later change can start it from the telemetry handler instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
archandatta
marked this pull request as ready for review
September 18, 2026 14:25
Sayan-
requested changes
Sep 18, 2026
Sayan-
left a comment
Contributor
There was a problem hiding this comment.
- p1:
S2StorageController.Stopclears its writer even when shutdown exits before draining or closing storage.everStartedthen prevents reopening, and later stops cannot reach the live writer. Reproduced 20/20 under race with a blocked append. - p2: the controller holds
muacrossstreamFn, writer startup, and the full stop. A blocked callback or stop makesStop(ctx)exceed its deadline while waiting for the lock and blocks both state accessors. Reproduced 20/20 under race. - p2:
Startlogs “S2 storage enabled” before startup succeeds. A canceled parent returns an error with both state flags false while retaining the enabled log. Reproduced 20/20 with captured logging.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4e921bb. Configure here.
| c.log.Info("S2 storage enabled", "basin", c.basin, "stream", stream) | ||
| c.mu.Lock() | ||
| c.writer, c.cancel, c.everStarted = w, cancel, true | ||
| c.mu.Unlock() |
There was a problem hiding this comment.
Writer can start after Stop returns
Medium Severity
If Stop times out while Start is still opening the append session, Start still publishes the writer afterward. Running is false when Stop returns, so a caller can treat the sink as down and later see events forwarded anyway.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 4e921bb. Configure here.
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.


Summary
S2StorageControllerinserver/lib/events/s2storage.go, a start/stop wrapper aroundS2StorageWriterthat resolves the stream name throughstreamFnatStartRunning()andEverStarted()so later callers can distinguish active forwarding from any prior S2 persistenceStart, failed-start rollback, empty config,StopwithoutStart, and post-Stopstate with unit testsWhy
An upcoming telemetry mode needs a browser instance to forward selected events without ever opening its S2 append session.
cmd/api/main.gostill opensS2StorageWriterdirectly at the existing boot and fork-identity start points; this branch only adds the lifecycle owner that a later change can wire in.Existing behavior is unchanged:
main.go,api.go,S2StorageWriter,StorageWriter, and S2 read-from-seq-0 behavior are untouched.Testing
cd server && GOCACHE=/tmp/go-build-cache GOMODCACHE=/tmp/go-mod-cache go test ./lib/events/ -count=1 -race— ok, includes new controller lifecycle and concurrency testscd server && GOCACHE=/tmp/go-build-cache GOMODCACHE=/tmp/go-mod-cache go build ./...— passedcd server && GOCACHE=/tmp/go-build-cache GOMODCACHE=/tmp/go-mod-cache go vet ./...— no findingsDOCKER_BUILDKIT=1 docker build -f images/chromium-headless/image/Dockerfile -t kernel-headless-test .— succeeded, imagesha256:270be0da270964970e71c99daf259f6c907225012352eb4f309e97332796f560S2_BASIN,S2_ACCESS_TOKEN, andS2_STREAMunset —GET /spec.yaml200, zeroS2 storagelines in/var/log/supervisord/kernel-images-apiS2_BASIN,S2_ACCESS_TOKEN, andS2_STREAM—GET /spec.yaml200, oneS2 storage enabledline in/var/log/supervisord/kernel-images-apiPUT /telemetry201,GET /telemetry200,POST /telemetry/events200, andGET /telemetry/stream?replay=alldelivered the posted event framedocker stop -t 30in both S2 modes — cleanshutdown signal received, zerodrain incomplete/drain deadline exceededwarningsNot run: real S2 credentials; none were available, so the S2-enabled live check used fake values and produced the expected submit ack error after posting an event.
Note
Low Risk
Additive library code and tests only; no production call sites wired yet, so runtime behavior is unchanged.
Overview
Introduces
S2StorageController, a mutex-guarded start/stop owner aroundS2StorageWriterso S2 forwarding can stay off until explicitly started—needed for telemetry modes that must not open an append session at boot.Startresolves the stream via astreamFn(so fork identity can be known later), skips work when basin/token or stream are empty (credentials missing does not callstreamFn), and opens at most one writer: repeated or concurrentStartis idempotent, andStartafterStopdoes not reopen.Stopwaits on in-flight start/stop, honors context cancellation, and leaves the writer in place if shutdown times out.Running()andEverStarted()expose active vs. ever-persisted state.Adds
s2storage_test.gowith lifecycle, concurrency, rollback, logging, and context behavior coverage.S2StorageWriterand server wiring are unchanged in this PR.Reviewed by Cursor Bugbot for commit 4e921bb. Bugbot is set up for automated code reviews on this repo. Configure here.