mirror of
https://github.com/block/buzz.git
synced 2026-11-03 07:51:22 +00:00
feat(relay): huddle-audio-unavailable guardrail under horizontal scaling (§5b)
Plan §5b, decided by Tyler: rather than sticky-route huddles or ship a
silent split-room, a horizontally-scaled deployment surfaces a clear,
client-handleable unavailable signal on huddle join.
- config: huddle_audio_available bool, env BUZZ_HUDDLE_AUDIO_AVAILABLE.
Defaults true so single-pod (N=1) deployments keep today's huddle
behavior unchanged. Operators running multiple relay pods set it false.
- audio handler: after auth + membership pass and BEFORE get_or_create joins
a room, if huddle_audio_available is false we send
{type:error, code:huddle_audio_unavailable, message:...} and return — no
silent room join whose frames never cross pods.
Why a config flag and not pod-count self-detection: the relay can't reliably
count its own pods; an explicit operator flag is the honest model and keeps
the §4 fork-B (any-pod-any-connection) generic routing free of huddle
stickiness. The real fix is the out-of-relay media/SFU service (Tyler's
long-term target), out of scope for this rewrite.
Tests: default-true (N=1 compat) and env-false-disables, both green. Full
buzz-relay --lib green at --test-threads=1 (374). Note for this lane: there
is a pre-existing parallel-run env-var race (global_presence_pubsub test
calls Config::from_env without the config tests' ENV_MUTEX guard) — not a
regression from this change; flagged to fix in the wiring lane.
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
This commit is contained in:
parent
b966eff547
commit
4de6715ac6
@@ -183,6 +183,35 @@ async fn handle_audio_connection(socket: WebSocket, state: Arc<AppState>, channe
|
||||
return;
|
||||
}
|
||||
|
||||
// Huddle audio guardrail (plan §5b). Audio frames are relayed only within
|
||||
// a single pod; under horizontal scaling (any-pod-any-connection) two peers
|
||||
// in one huddle can land on different pods and never hear each other. A
|
||||
// multi-pod deployment sets `huddle_audio_available = false`, and we surface
|
||||
// a clear, client-handleable "unavailable" signal here — BEFORE joining a
|
||||
// room — rather than shipping a silent split-room. Single-pod deployments
|
||||
// leave the flag at its `true` default and keep today's behavior. The fix
|
||||
// is an out-of-relay media/SFU service (Tyler's long-term target), not
|
||||
// sticky-routing huddles into this rewrite.
|
||||
if !state.config.huddle_audio_available {
|
||||
debug!(
|
||||
channel_id = %channel_id,
|
||||
pubkey = %pubkey_hex,
|
||||
"huddle audio unavailable under horizontal scaling — rejecting join"
|
||||
);
|
||||
let _ = ws_send
|
||||
.send(WsMessage::Text(
|
||||
serde_json::json!({
|
||||
"type": "error",
|
||||
"code": "huddle_audio_unavailable",
|
||||
"message": "huddle audio unavailable in this deployment"
|
||||
})
|
||||
.to_string()
|
||||
.into(),
|
||||
))
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
let room = state.audio_rooms.get_or_create(channel_id);
|
||||
|
||||
// Re-check archived status after obtaining the room. This closes the
|
||||
|
||||
@@ -80,6 +80,23 @@ pub struct Config {
|
||||
/// are permitted regardless of auth method (API token, NIP-42).
|
||||
pub require_relay_membership: bool,
|
||||
|
||||
/// Whether this deployment can serve huddle (voice) audio.
|
||||
///
|
||||
/// Huddle audio frames are relayed peer-to-peer *within a single pod*
|
||||
/// (`AudioRoomManager` is an in-process map; only huddle lifecycle events
|
||||
/// cross pods via Redis). Under horizontal scaling (any-pod-any-connection,
|
||||
/// plan §4 fork B) two peers in the same huddle can land on different pods
|
||||
/// and never hear each other. Rather than sticky-route huddles or ship a
|
||||
/// silent split-room (plan §5b, decided by Tyler), a horizontally-scaled
|
||||
/// deployment sets this `false` and the relay surfaces a clear, client-
|
||||
/// handleable "huddle audio unavailable" signal on join.
|
||||
///
|
||||
/// Defaults to `true` so single-pod deployments (the N=1 case) keep today's
|
||||
/// behavior unchanged. Operators running multiple relay pods MUST set
|
||||
/// `BUZZ_HUDDLE_AUDIO_AVAILABLE=false` until the out-of-relay media/SFU
|
||||
/// service lands.
|
||||
pub huddle_audio_available: bool,
|
||||
|
||||
/// Optional hex-encoded pubkey of the relay owner.
|
||||
/// When set, this pubkey is automatically bootstrapped into `relay_members`
|
||||
/// with the `owner` role on first startup.
|
||||
@@ -190,6 +207,12 @@ impl Config {
|
||||
.map(|v| v == "true" || v == "1")
|
||||
.unwrap_or(false);
|
||||
|
||||
// Defaults true → single-pod (N=1) keeps today's huddle behavior. A
|
||||
// horizontally-scaled deployment sets this false; see the field doc.
|
||||
let huddle_audio_available = std::env::var("BUZZ_HUDDLE_AUDIO_AVAILABLE")
|
||||
.map(|v| !(v == "false" || v == "0"))
|
||||
.unwrap_or(true);
|
||||
|
||||
let allow_nip_oa_auth = std::env::var("BUZZ_ALLOW_NIP_OA_AUTH")
|
||||
.map(|v| v == "true" || v == "1")
|
||||
.unwrap_or(false);
|
||||
@@ -390,6 +413,7 @@ impl Config {
|
||||
metrics_port,
|
||||
pubkey_allowlist_enabled,
|
||||
require_relay_membership,
|
||||
huddle_audio_available,
|
||||
relay_owner_pubkey,
|
||||
allow_nip_oa_auth,
|
||||
media,
|
||||
@@ -440,6 +464,22 @@ mod tests {
|
||||
!config.allow_nip_oa_auth,
|
||||
"allow_nip_oa_auth should default to false"
|
||||
);
|
||||
assert!(
|
||||
config.huddle_audio_available,
|
||||
"huddle_audio_available should default to true so single-pod (N=1) keeps today's huddle behavior"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn huddle_audio_available_can_be_disabled_for_horizontal_scaling() {
|
||||
let _guard = ENV_MUTEX.lock().unwrap();
|
||||
std::env::set_var("BUZZ_HUDDLE_AUDIO_AVAILABLE", "false");
|
||||
let config = Config::from_env().expect("config");
|
||||
std::env::remove_var("BUZZ_HUDDLE_AUDIO_AVAILABLE");
|
||||
assert!(
|
||||
!config.huddle_audio_available,
|
||||
"BUZZ_HUDDLE_AUDIO_AVAILABLE=false must disable huddle audio (multi-pod deployments)"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user