Skip to content

backend-plan: wire push + data_plane consume endpoint (Phase 2+3) - #438

Closed
zzylol wants to merge 2 commits into
feat/backend-plan-from-stage-configfrom
feat/backend-plan-wire-push
Closed

zzylol wants to merge 2 commits into
feat/backend-plan-from-stage-configfrom
feat/backend-plan-wire-push

Conversation

@zzylol

@zzylol zzylol commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Stacked on #437 (Phase 1). Phases 2+3 of the BackendPlan cutover (control_plane/docs/design-backend-plan-wire-format.md): the control plane now actually pushes an encoded BackendPlan to a new POST /api/v1/backend-plan endpoint, alongside (not instead of) the legacy streaming-config/storage_routing documents. Nothing consumes the installed plan yet — that's Phase 4, tracked separately.

  • BackendClient::post_backend_plan_typed — new typed POST method, same transient/permanent classification as the existing typed methods, hitting a sibling endpoint derived from the configured streaming-config URL.
  • emit::backend_push::push_cumulative_entries (the one real call site that builds BackendStageConfig for a live push) now also builds a BackendPlan via backend_plan::from_stage_config (backend-plan: construct BackendPlan from BackendStageConfig (Phase 1) #437) from the same cumulative_be snapshot, and fires a best-effort, single-attempt push. Its outcome never affects PushOutcome — nothing depends on it succeeding yet, and a failure must stay invisible to real callers.
  • data_plane: HotReloadBackendPlan (same ArcSwap shape as HotReloadStreamingConfig) + GET/POST /api/v1/backend-plan handlers, wired into main.rs with an empty bootstrap handle (mirrors the existing storage-routing bootstrap pattern).

Test plan

  • cargo test --release -p control_plane --lib backend_client:: backend_push:: — including a dedicated test proving the plan push fires alongside the coupled push, and a test proving a plan-push failure does NOT flip PushOutcome.
  • cargo test --release -p data_plane --lib — 912/912 pass (2 pre-existing ignores), including new HotReloadBackendPlan round-trip + 503 + bad-bytes tests.
  • cargo build --release --workspace — clean.
  • Confirmed the 2 pre-existing e2e_controller_plans_and_backend_serves failures (*_topk cases) reproduce identically on main — not a regression from this change.

Combines the wire push and endpoint pieces of the BackendPlan cutover
(control_plane/docs/design-backend-plan-wire-format.md):

control_plane side:
- BackendClient::post_backend_plan_typed posts encoded BackendPlan bytes
  to POST /api/v1/backend-plan (sibling endpoint derived from the
  configured streaming-config URL, same convention as storage_routing).
- emit::backend_push::push_cumulative_entries now also builds a
  BackendPlan from the same cumulative_be snapshot used for the legacy
  streaming-config/storage-routing documents (via
  backend_plan::from_stage_config from the prior PR) and fires a
  best-effort, single-attempt push alongside the existing coupled push.
  This is the real plan-time call site (Phase 3) -- the only place that
  builds BackendStageConfig for a live push.
- The plan push's outcome never affects PushOutcome, which existing
  callers key real (legacy-path) behavior on -- nothing consumes
  BackendPlan yet, so its failure must stay invisible to them. No
  in-function retry loop (unlike the coupled documents): the next
  replan cycle is the retry backstop, matching push_or_log's existing
  fire-and-forget contract for the legacy YAML path.

data_plane side:
- HotReloadBackendPlan (storage_engines/types/hot_reload_config.rs):
  same ArcSwap-snapshot/swap shape as HotReloadStreamingConfig, applied
  to control_plane::backend_plan::BackendPlan.
- GET/POST /api/v1/backend-plan handlers, registered alongside (not
  replacing) /api/v1/streaming-config. POST decodes protobuf bytes and
  atomically swaps; does not touch the sid catalog or SketchStore
  reconciliation.
- main.rs installs an empty handle at startup so the endpoints don't
  503 before the control plane's first push lands, mirroring the
  existing backend-storage-routing bootstrap pattern.

Nothing consumes the installed BackendPlan yet -- that's Phase 4
(serving-time cutover), which also retires ObservedFamilyCostModel's
SketchStore-reconstruction to a fallback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace forward references to "Phase 4"/"nothing consumes this yet"
(stale now that the serving-time consumer exists) with descriptions of
the actual current architecture: BackendPlan is read by ASAPQueryEngine's
serving-time lookup, sits alongside (not in place of) the legacy
streaming-config path, and a dropped push just falls back to SketchStore
reconstruction until the next replan cycle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@zzylol
zzylol deleted the branch feat/backend-plan-from-stage-config July 30, 2026 04:56
@zzylol zzylol closed this Jul 30, 2026
@zzylol
zzylol deleted the feat/backend-plan-wire-push branch July 30, 2026 05:01
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