WIP: streamer Start takes a ctx; README and TODO
check / check (push) Canceled after 0s

Model: opus-5-5
This commit is contained in:
2026-10-14 13:04:16 +00:00
parent 50c8e9d276
commit 465e3ea292
5 changed files with 27 additions and 15 deletions
+14 -8
View File
@@ -273,24 +273,30 @@ standard: normalized scripts in `script/` are the entrypoints for the
development workflow, and the Makefile targets are thin shims that call development workflow, and the Makefile targets are thin shims that call
them. We provide: them. We provide:
- `script/bootstrap` — install all development dependencies (go, Tests and the linter run only in Docker, as the `test` and `lint` phases of the
golangci-lint, Go module download) `Dockerfile`; the image cannot be built unless both pass. Every `docker build`
in `script/` passes `--no-cache`, so each run executes every check.
- `script/bootstrap` — install all development dependencies (git, make, go, Go
module download); warns when docker is missing
- `script/setup` — make a fresh clone ready for development: runs - `script/setup` — make a fresh clone ready for development: runs
`script/bootstrap`, then `script/install-precommit` `script/bootstrap`, then `script/install-precommit`
- `script/projectname` — print the project name (used for the Docker - `script/projectname` — print the project name (used for the Docker
image tag) image tag)
- `script/test` — run the test suite - `script/test` — build the `test` phase alone, which runs
(`go test -short -timeout 30s -race -cover ./...`, verbose rerun on `go test -short -timeout 90s -race -cover ./...` (verbose rerun on failure).
failure). The `-short` flag skips the live-network integration test so the The `-short` flag skips the live-network integration test so the run is
default run is deterministic and offline. deterministic and offline.
- `script/lint` — run `go vet ./...` and `golangci-lint run` - `script/lint` — build the `lint` phase alone, which runs golangci-lint
v2.14.0 with `.golangci.yml`
- `script/fmt` — format all code (writes) - `script/fmt` — format all code (writes)
- `script/fmt-check` — check formatting (read-only) - `script/fmt-check` — check formatting (read-only)
- `script/check` — run `script/test`, `script/lint`, and - `script/check` — run `script/test`, `script/lint`, and
`script/fmt-check` `script/fmt-check`
- `script/docker` — build the Docker image tagged via - `script/docker` — build the Docker image tagged via
`script/projectname` `script/projectname`
- `script/cibuild` — CI entrypoint: `docker build .` - `script/cibuild` — CI entrypoint: runs `script/bootstrap` and
`script/check`, then builds the image
- `script/precommit` — pre-commit gate: `go mod tidy` + `go fmt` (must - `script/precommit` — pre-commit gate: `go mod tidy` + `go fmt` (must
not change files), then `script/check` not change files), then `script/check`
- `script/install-precommit` — install the git pre-commit hook that - `script/install-precommit` — install the git pre-commit hook that
+7 -2
View File
@@ -10,8 +10,9 @@
# Status # Status
pre-1.0. No git tags. The Docker build runs the format check, the linter pre-1.0. No git tags. The linter and the tests are phases of the Docker
and the tests, and the Gitea workflow runs that build on every push. The build, and the Gitea workflow runs `script/cibuild` (the format check, both
phases, then the image) on every push. The
image sets memory ceilings for a 5 GiB container (README "Memory") and the image sets memory ceilings for a 5 GiB container (README "Memory") and the
README says how to run it under upaas (README "Running under upaas"). A README says how to run it under upaas (README "Running under upaas"). A
35-hour run of `3898daa` on the live feed peaked at about 1 GiB, without a 35-hour run of `3898daa` on the live feed peaked at about 1 GiB, without a
@@ -27,6 +28,10 @@ real 5 GiB limit (https://git.eeqj.de/sneak/routewatch/issues/3).
# Completed Steps # Completed Steps
- 2026-10-14: the shared files are re-vendored from `sneak/prompts` at
`dd4027b`: golangci-lint v2.14.0 and its configuration, lint and test as
separate uncached Dockerfile phases, agent guidance in `AGENTS.md`; the code
is fixed for what the new linter configuration finds (closes #52)
- 2026-10-03: `/api/v1/stats` serves the prefix distribution from memory, - 2026-10-03: `/api/v1/stats` serves the prefix distribution from memory,
seeded at startup and adjusted on every live-route write, so a request no seeded at startup and adjusted on every live-route write, so a request no
longer reads every live route (closes #30) longer reads every live route (closes #30)
+1 -1
View File
@@ -31,7 +31,7 @@ func main() {
// Start streaming before any defer: log.Fatal exits without running // Start streaming before any defer: log.Fatal exits without running
// deferred calls. // deferred calls.
err := s.Start() err := s.Start(context.Background())
if err != nil { if err != nil {
log.Fatal("Failed to start streamer:", err) log.Fatal("Failed to start streamer:", err)
} }
+1 -1
View File
@@ -109,7 +109,7 @@ func (rw *RouteWatch) Run(ctx context.Context) error {
// No longer need routing table handler - PrefixHandler maintains live_routes table // No longer need routing table handler - PrefixHandler maintains live_routes table
// Start streaming // Start streaming
err := rw.streamer.Start() err := rw.streamer.Start(ctx)
if err != nil { if err != nil {
return err return err
} }
+4 -3
View File
@@ -188,8 +188,9 @@ func (s *Streamer) RegisterRawHandler(handler RawMessageHandler) {
// Start begins streaming BGP updates from the RIS Live API in a background goroutine. // Start begins streaming BGP updates from the RIS Live API in a background goroutine.
// It starts worker goroutines for each registered handler and manages automatic // It starts worker goroutines for each registered handler and manages automatic
// reconnection with exponential backoff on connection failures. // reconnection with exponential backoff on connection failures.
// Returns an error if the streamer is already running. // Returns an error if the streamer is already running. It streams until Stop:
func (s *Streamer) Start() error { // the end of ctx does not stop it.
func (s *Streamer) Start(ctx context.Context) error {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
@@ -197,7 +198,7 @@ func (s *Streamer) Start() error {
return errAlreadyRunning return errAlreadyRunning
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.WithoutCancel(ctx))
s.cancel = cancel s.cancel = cancel
s.running = true s.running = true