fix: clear stale federated presence on GlobalRoomInactive
Some checks failed
Mirror to GitHub / mirror (push) Failing after 34s
Build Release Binaries / build-amd64 (push) Failing after 7m37s

When a remote relay's room goes inactive (all participants left),
the receiving relay now:
1. Clears remote_participants for that peer+room
2. Broadcasts updated RoomUpdate to local clients with the remote
   participant removed
3. Updates federation_active_rooms metric

Previously, remote participants lingered in the participant list
after disconnect, causing ghost entries and stale media forwarding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-08 13:06:48 +04:00
parent 5c24adf1c1
commit fc721c4217

View File

@@ -597,9 +597,18 @@ async fn handle_signal(
let mut links = fm.peer_links.lock().await;
if let Some(link) = links.get_mut(peer_fp) {
link.active_rooms.remove(&room);
// Clear remote participants for this peer+room
link.remote_participants.remove(&room);
// Also try canonical name
if let Some(canonical) = fm.resolve_global_room(&room) {
link.remote_participants.remove(canonical);
}
}
// Update active rooms gauge
// Update active rooms metric
let total: usize = links.values().map(|l| l.active_rooms.len()).sum();
fm.metrics.federation_active_rooms.set(total as i64);
// Check if any other peer still has this room — if none, propagate inactive
let any_other_active = links.iter()
.any(|(fp, l)| fp != peer_fp && l.active_rooms.contains(&room));
@@ -614,6 +623,37 @@ async fn handle_signal(
}
}
}
drop(links);
// Broadcast updated RoomUpdate to local clients (remote participant removed)
let mgr = fm.room_mgr.lock().await;
for local_room in mgr.active_rooms() {
if fm.is_global_room(&local_room) && fm.resolve_global_room(&local_room) == fm.resolve_global_room(&room) {
let mut all_participants = mgr.local_participant_list(&local_room);
// Merge remaining remote participants from other peers
let links = fm.peer_links.lock().await;
for link in links.values() {
if let Some(canonical) = fm.resolve_global_room(&local_room) {
if let Some(remote) = link.remote_participants.get(canonical) {
all_participants.extend(remote.iter().cloned());
}
if let Some(remote) = link.remote_participants.get(&local_room) {
all_participants.extend(remote.iter().cloned());
}
}
}
let update = SignalMessage::RoomUpdate {
count: all_participants.len() as u32,
participants: all_participants,
};
let senders = mgr.local_senders(&local_room);
drop(links);
drop(mgr);
room::broadcast_signal(&senders, &update).await;
info!(room = %room, "broadcast updated presence (remote participant removed)");
break;
}
}
}
_ => {} // ignore other signals
}