Skip to content

feat: unify the recording/forwarding configuration interface. - #6

Merged
JosiahBull merged 2 commits into
mainfrom
jo/hotfix-unify-recording-config
Jun 16, 2026
Merged

feat: unify the recording/forwarding configuration interface.#6
JosiahBull merged 2 commits into
mainfrom
jo/hotfix-unify-recording-config

Conversation

@JosiahBull

@JosiahBull JosiahBull commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Recording storage was configured cluster-wide (ProxyClusterBuilder::storage(...)) while replay was configured per-upstream (a ReplaySource passed to add_upstream_with). The two halves of the same record→replay round-trip were wired through different mechanisms and didn't reference each other — so it was easy to set a replay source per upstream and assume recording would land in the same place, when in fact recording went to a single shared sink (or, with no .storage(...) call, to an in-memory ring that was silently discarded on shutdown).

This PR unifies the two: storage is now configured per upstream, and a single medium drives both directions.

What changed

Public API (breaking)

  • Removed ProxyClusterBuilder::storage(...) and the cluster-wide storage field.
  • New Snapshots bundle type — the single per-upstream storage knob:
    • Snapshots::from_storage(storage, strategy) — a durable medium (e.g. a JSONL file) used as both the replay source (loaded + indexed at run()) and the recording sink (appended to in Mode::Record).
    • Snapshots::in_memory(exchanges, strategy) — a replay-only source, never written back (tests/fixtures).
  • add_upstream_with / add_upstream_with_mode now take Option<Snapshots> instead of Option<ReplaySource>.
  • Recorder::with_storage(cfg, Option<SharedStorage>)Recorder::with_routes(cfg, HashMap<String, SharedStorage>).
  • Recorder::storage()Recorder::storage_for(&str).

Internals

  • The recorder stays cluster-wide for the in-memory ring + assertion API (QueryTraffic/AssertSeen/AssertCount are unchanged), but durable storage became a route map keyed by upstream name: record() appends each exchange to its own upstream's medium (durable-before-memory ordering preserved), and flush() fences every backend.
  • At run() (already async), each upstream's Snapshots is resolved — its existing contents stream into the indexed ReplaySource, and a durable medium is registered as that upstream's recording sink.

Versioning

  • Bumped 0.3.0 → 0.4.0. The API removals/signature changes are breaking; under Cargo's semver for 0.x that's a minor bump, which clears the failing cargo semver-checks gate. Workspace version + internal dep entries + Cargo.lock updated in lock-step.

Docs

  • SPECIFICATION.md §3.3, §4, §4.1, §6.4, §8, §9.1, §9.2, §20.1 updated to describe per-upstream Snapshots; removed the dead persist_path / ProxyClusterBuilder::storage references.

Migration

// before
let builder = ProxyClusterBuilder::new()
    .storage(storage)
    .add_upstream_with("api", cfg, mw, Some(replay_source));

// after — one medium per upstream, used for record + replay
let builder = ProxyClusterBuilder::new()
    .add_upstream_with(
        "api", cfg, mw,
        Some(Snapshots::from_storage(storage, MatchStrategy::MethodUriAndBodyHash)),
    );

Behavior note

Because the medium feeds replay too, a re-run in Mode::Record replays any request already present in the file rather than re-recording it (the snapshot acts as a dedup cache, §8.3) and only forwards genuinely new requests. Delete the file to force a clean re-capture.

Testing

  • cargo build --workspace --all-targets — clean
  • cargo test -p partly-proxy-lib — all suites pass (record 5/5, replay 11/11, lib units 73/73)
  • cargo clippy -p partly-proxy-lib --all-targets — clean

@JosiahBull
JosiahBull merged commit 4354494 into main Jun 16, 2026
3 checks passed
@JosiahBull
JosiahBull deleted the jo/hotfix-unify-recording-config branch June 16, 2026 03:58
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