Skip to content

edge: add feed runner, manager, HTTP API, and CLI#3524

Draft
armcconnell wants to merge 1 commit intoedge/2-sinksfrom
edge/3-runner-manager-cli
Draft

edge: add feed runner, manager, HTTP API, and CLI#3524
armcconnell wants to merge 1 commit intoedge/2-sinksfrom
edge/3-runner-manager-cli

Conversation

@armcconnell
Copy link
Copy Markdown
Contributor

Part 3 of 4 — edge feed parser stack

  1. edge: add Top-of-Book parser framework #3522 — edge: add Top-of-Book parser framework ← start here
  2. edge: add JSON/CSV/Unix-socket output sinks #3523 — edge: add JSON/CSV/Unix-socket output sinks
  3. this PR — edge: add feed runner, manager, HTTP API, and CLI
  4. edge: add integration tests, synthetic publisher, and devnet guide (coming)

Draft until the prior two land. This is the PR where the edge feature turns on — after it merges, operators can call `doublezero edge enable` and a feed will actually flow.

Summary

  • `Runner` owns one feed: two multicast listener goroutines (marketdata + refdata on separate UDP ports), a parser (edge: add Top-of-Book parser framework #3522), a sink (edge: add JSON/CSV/Unix-socket output sinks #3523), and atomic counters. A periodic goroutine logs a liveness summary every 30s so operators can see activity without polling the API.
  • `Manager` owns many runners keyed by code. `Enable` / `Disable` / `Close` lifecycle is owned by the manager, not by HTTP request context. This is deliberate: the runner context is explicitly rooted in the manager's lifetime, not the caller's, so an HTTP handler returning does not tear down the feed.
  • HTTP endpoints `ServeEnable` / `ServeDisable` / `ServeStatus` exposed on the existing doublezerod Unix socket API.
  • Rust CLI adds `doublezero edge enable/disable/status` subcommands with `--marketdata-port` / `--refdata-port` flags. Status supports `--json` for machine-readable output.
  • `runtime/run.go` wires the manager against the existing serviceability reader (to resolve group codes to multicast IPs) and the existing user manager (for onchain subscription checks), so edge feeds respect the allowlist automatically.

Testing Verification

  • Manager unit tests cover port validation (required, must-differ), subscription enforcement, and lifecycle transitions.
  • Validated against real testnet Top-of-Book traffic on a QA node: deployed a patched doublezerod, ran `edge enable` against a real multicast group with an onchain subscription, and confirmed both sockets bound, IGMP membership established, and records flowed end-to-end at sustained throughput (>1M records over the test window) with `buffered=0` after the first refdata cycle.

Size note

~625 production lines across Go + Rust, slightly above the ~500-line target. The unit is cohesive (runner lifecycle + HTTP surface + CLI binding) and splitting further would leave intermediate states where the feature compiles but can't be invoked end-to-end.

Wires the parser and sinks into the doublezerod daemon so operators
can actually enable a feed. This is the commit where the edge feature
turns on end-to-end.

Runner owns one feed: two multicast listener goroutines (marketdata
on one UDP port, refdata on another), a parser, a sink, and a small
set of atomic counters. Each listener joins the multicast group,
reads frames in a loop, hands them to the parser, and forwards any
produced records to the sink. A periodic goroutine logs a summary
every 30s so operators can see liveness without polling the API.

Manager owns many runners keyed by code. Enable(cfg) validates the
config (required ports, both must differ, resolver + subscription
checks, parser/sink factories), constructs a runner, starts it with
a long-lived context owned by the manager, and stores it. Disable(code)
and Close() cancel the runner context and release the sink. HTTP
endpoints ServeEnable / ServeDisable / ServeStatus are thin wrappers
over those methods and expose them on the existing doublezerod
Unix socket API. Critically, Enable takes no ctx from the caller —
the runner's lifetime is owned by the manager, not by the HTTP
request, so the request finishing does not tear down the feed.

On the operator side, adds `doublezero edge enable/disable/status`
subcommands to the Rust CLI, communicating with doublezerod over
its Unix socket. The enable command takes --code, --parser, --format,
--output, --marketdata-port, and --refdata-port. Status supports
--json for machine-readable output.

runtime/run.go wires up the manager: resolves multicast group codes
to IPs via the existing serviceability reader and routes subscription
checks through the existing user manager, so the edge feature
automatically respects onchain allowlists.
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.

1 participant