From a9376b3b0400cfee4e8ff07d35db9dcaee939016 Mon Sep 17 00:00:00 2001 From: timedout Date: Fri, 29 May 2026 14:53:15 +0100 Subject: [PATCH] fix: Hold a federation room lock while remotely joining a room --- src/service/rooms/membership/mod.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/service/rooms/membership/mod.rs b/src/service/rooms/membership/mod.rs index b73473a81..e88aa33d6 100644 --- a/src/service/rooms/membership/mod.rs +++ b/src/service/rooms/membership/mod.rs @@ -34,7 +34,7 @@ use crate::{ Dep, antispam, globals, rooms::{ - metadata, outlier, pdu_metadata, short, + event_handler, metadata, outlier, pdu_metadata, short, state::{self, RoomMutexGuard}, state_accessor, state_cache, state_compressor::{self, CompressedState, HashSetCompressStateEvent}, @@ -51,6 +51,7 @@ struct Services { server: Arc, db: Arc, antispam: Dep, + event_handler: Dep, globals: Dep, metadata: Dep, outlier: Dep, @@ -73,6 +74,7 @@ fn build(args: crate::Args<'_>) -> Result> { server: args.server.clone(), db: args.db.clone(), antispam: args.depend::("antispam"), + event_handler: args.depend::("rooms::event_handler"), globals: args.depend::("globals"), metadata: args.depend::("rooms::metadata"), outlier: args.depend::("rooms::outlier"), @@ -380,8 +382,6 @@ pub async fn join_remote_room( // It has enough fields to be called a proper event now let mut join_event = join_event_stub; - - info!("Asking {remote_server} for send_join in room {room_id}"); let send_join_request = federation::membership::create_join_event::v2::Request::new( room_id.to_owned(), event_id.clone(), @@ -391,6 +391,18 @@ pub async fn join_remote_room( .await, ); + // NOTE: send_join can take a long time to respond, but from the point of view + // of other servers, we may already have finished joining. This means they + // sometimes end up sending PDUs to us that we aren't yet ready to accept, and + // consequently drop. Holding the mutex over the room while processing mitigates + // this. + let _room_lock = self + .services + .event_handler + .mutex_federation + .lock(room_id.as_str()) + .await; + info!("Asking {remote_server} for send_join in room {room_id}"); let send_join_response = match self .services .sending