Skip to content

perf(relay): serve relay-membership checks from the read replica - #4124

Merged
tlongwell-block merged 1 commit into
mainfrom
eva/relay-member-replica-read
Aug 1, 2026
Merged

perf(relay): serve relay-membership checks from the read replica#4124
tlongwell-block merged 1 commit into
mainfrom
eva/relay-member-replica-read

Conversation

@tlongwell-block

Copy link
Copy Markdown
Collaborator

Summary

Route Db::is_relay_member — the membership check that runs on every authenticated HTTP request and WS AUTH — through the standard route_read machinery on the bounded arm, instead of adding a bespoke cache (replaces #3844).

  • crates/buzz-db/src/relay_members.rs: add is_relay_member_on(&mut PgConnection, ...) executor seam; the pool version delegates to it.
  • crates/buzz-db/src/lib.rs: Db::is_relay_member now routes via route_read("relay_membership", RoutePredicate::Bounded) — replica only on a proved fresh session, writer on any route rejection, writer re-run on replica query error. Exactly the shape of every other routed read.

This is the one permission read served from the replica, by explicit product decision (Tyler accepted ≤1s bounded staleness on reads we choose): the fleet-wide fence guarantee (BUZZ_REPLICA_READ_MAX_AGE_MS, deploy target 1s) is an order of magnitude tighter than the 10s TTL proposed in #3844 and needs no invalidation machinery. Staleness is symmetric for admits and revokes. BUZZ_REPLICA_READ_MAX_AGE_MS unset = writer-only = kill switch. It is not precedent for routing other permission reads.

Validation

At this exact commit (git rev-parse HEAD confirmed in the same shell, rustc 1.95):

  • cargo test -p buzz-db — 94 passed, 0 failed
  • PG-gated suite single-threaded — 151 passed, 2 failed; the 2 failures are the per-owner-limit tests broken on main by feat(relay): raise hosted community limit to five #3829 (limit 3→5, tests still seed 3) — they fail identically at base 19d57b0d4 in a pristine control checkout; separate trivial fix to follow
  • New PG-gated test is_relay_member_is_bounded_routed_and_fails_closed — divergent writer/replica fixtures prove: budget unset ⇒ writer; budget set + fresh proof ⇒ replica; over-budget entry ⇒ writer
  • clippy -D warnings + fmt clean; pre-push hooks green (desktop check/test, rust tests, tauri checks)
  • Live-local pass (TESTING.md, release binary, BUZZ_REQUIRE_RELAY_MEMBERSHIP=true, fresh DB):
    • writer-only (no READ_DATABASE_URL): member accepted, outsider 403 relay_membership_required; metrics route_decision{path="relay_membership",decision="writer",reason="disabled"}
    • replica configured + BUZZ_REPLICA_READ_MAX_AGE_MS=1000: member accepted / outsider denied via decision="replica",reason="fresh"; admit visible to the routed check within ~1.2s; revoke enforced within ~1.2s
    • reader outage mid-flight (TCP proxy killed): member send still succeeds in <200ms via decision="writer",reason="reader_acquire_timeout"; outsider still denied — fails closed, no availability loss

Reviewed by Wren: 9/10 minimalness, 9/10 elegance, 9.5/10 correctness at this SHA.

Supersedes the 10s-cache approach in PR 3844, which should be closed unmerged once this lands.

Route Db::is_relay_member through route_read on the bounded arm, the
same proved-reader-session contract as every other routed read: a
replica answer is served only when the session's heartbeat observation
proves an entry within the configured budget
(BUZZ_REPLICA_READ_MAX_AGE_MS, deploy target 1s); anything else —
budget unset, fence closed/stale, proof behind, replica error — fails
closed to the writer.

This replaces the 10s relay-membership cache proposed in #3844: the
bounded-staleness contract is already guaranteed fleet-wide by the
replica fence, is an order of magnitude tighter than a 10s TTL, and
needs no invalidation machinery.

The check runs on every authenticated HTTP request and WS AUTH, so
this moves the relay's hottest auth query off the writer pool wherever
a replica is configured. It is deliberately the one permission read
that routes — not precedent for others.

Co-authored-by: Tyler <109685178+tlongwell-block@users.noreply.github.com>
Signed-off-by: Tyler <109685178+tlongwell-block@users.noreply.github.com>
@tlongwell-block
tlongwell-block requested a review from a team as a code owner August 1, 2026 14:23
@tlongwell-block
tlongwell-block merged commit ac4fa13 into main Aug 1, 2026
33 checks passed
@tlongwell-block
tlongwell-block deleted the eva/relay-member-replica-read branch August 1, 2026 17:32
tlongwell-block pushed a commit that referenced this pull request Aug 1, 2026
Brings in #4124: relay-membership checks served from the read replica
via bounded routed read. No conflicts.

Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
tellaho added a commit that referenced this pull request Aug 1, 2026
* origin/main: (24 commits)
  perf(relay): serve relay-membership checks from the read replica (#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (#3426)
  docs(readme): clarify which release asset to download per platform (#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (#3998)
  docs: note that addressable channel events scope by d, not h (#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (#2613)
  fix(desktop): keep thread-open affordance in archived channels (#4012)
  docs: add one-click Railway deploy for a hosted relay (#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (#3909)
  fix(desktop): preserve first huddle speech (#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (#3171)
  fix(release): preserve main in desktop PR body (#3979)
  chore(release): release Buzz Desktop version 0.5.3 (#3972)
  fix(release): require exact-head approval for desktop tags (#3973)
  fix(release): make desktop tagging squash-safe (#3965)
  ...

Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tellaho added a commit that referenced this pull request Aug 1, 2026
…onfig

* origin/main:
  perf(relay): serve relay-membership checks from the read replica (#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (#3426)
  docs(readme): clarify which release asset to download per platform (#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (#3998)
  docs: note that addressable channel events scope by d, not h (#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (#2613)
  fix(desktop): keep thread-open affordance in archived channels (#4012)
  docs: add one-click Railway deploy for a hosted relay (#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (#3909)
  fix(desktop): preserve first huddle speech (#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (#3171)
  fix(release): preserve main in desktop PR body (#3979)
  chore(release): release Buzz Desktop version 0.5.3 (#3972)
  fix(release): require exact-head approval for desktop tags (#3973)
  fix(release): make desktop tagging squash-safe (#3965)

Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
tellaho added a commit that referenced this pull request Aug 2, 2026
- Incorporate upstream desktop changes required by the pre-push overlap guard
- Preserve the link preview thumbnail stabilization work on the updated base

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>

* origin/main: (26 commits)
  docs: formal spec for remote agents and their management (#3748)
  fix(nip-oa): accept raw Nostr tag form in parse_json_array (#4203)
  perf(relay): serve relay-membership checks from the read replica (#4124)
  chore(deps): bump nostr-relay-pool for RUSTSEC-2026-0224 (#4139)
  docs(nostr): document #h requirement for live reaction subscriptions (#3487)
  docs(chart): fix ArgoCD example for native OCI sources (full artifact repoURL + path) (#3426)
  docs(readme): clarify which release asset to download per platform (#3481)
  fix(relay): allow open relays to set their NIP-11 workspace icon (kind:9033) (#3998)
  docs: note that addressable channel events scope by d, not h (#4103)
  docs: fix stale kind count, quick-start numbering, and empty Further Reading (#2613)
  fix(desktop): keep thread-open affordance in archived channels (#4012)
  docs: add one-click Railway deploy for a hosted relay (#2733)
  fix(desktop): point Oh My Pi preset at omp.sh (#3516)
  fix(mesh): stop restarting a busy or loading shared-compute node (#3909)
  fix(desktop): preserve first huddle speech (#3962)
  feat(desktop): Agent Trading Cards — mintable agent-snapshot card PNGs with optional NIP-44 lock (#3278)
  fix(buzz-acp): thread cache-read tokens into NIP-AM kind:44200 events (#3999)
  feat(relay): accept kind:30621 multi-repo projects at ingest (#3171)
  fix(release): preserve main in desktop PR body (#3979)
  chore(release): release Buzz Desktop version 0.5.3 (#3972)
  ...

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
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.

2 participants