fix: Ask more servers for state_ids when origin fails to provide

Some servers reference events in prev_events that they might not yet have finished processing, so this allows us to at least attempt to get the state from another trustworthy server in the room that might be faster. I don't think this is too effective, however it's more effective than giving up immediately.
This commit is contained in:
timedout authored and Jade Ellis committed 2026-06-27 20:16:48 +01:00
1 parent 3a7259250b
commit 8d4a313657
1 file changed
+44 -4
+44 -4
View File
@@ -6,9 +6,9 @@ use std::{
use conduwuit::{
Err, Event, PduEvent, Result, debug, debug_warn, err, error, trace, utils::IterStream, warn,
};
use futures::StreamExt;
use futures::{StreamExt, TryFutureExt, future::select_ok};
use ruma::{
EventId, OwnedEventId, RoomId, ServerName,
EventId, OwnedEventId, OwnedRoomId, RoomId, ServerName,
api::federation::event::{get_room_state, get_room_state_ids},
};
@@ -35,7 +35,7 @@ impl super::Service {
event_id: &EventId,
) -> Result<Option<HashMap<u64, OwnedEventId>>> {
trace!(%origin, "Asking remote for state_ids");
let res: get_room_state_ids::v1::Response = self
let res: get_room_state_ids::v1::Response = match self
.services
.sending
.send_federation_request(
@@ -43,7 +43,20 @@ impl super::Service {
get_room_state_ids::v1::Request::new(event_id.to_owned(), room_id.to_owned()),
)
.await
.inspect_err(|e| debug_warn!("Fetching state for event failed: {e}"))?;
.inspect_err(|e| debug_warn!("Fetching state for event failed: {e}"))
{
| Ok(resp) => Ok(resp),
| Err(e) =>
if e.is_not_found() {
self.fetch_state_ids_from_backfill_servers(
event_id.to_owned(),
room_id.to_owned(),
)
.await
} else {
Err(e)
},
}?;
debug!(events = res.pdu_ids.len(), "Fetching state events");
let mut state_events: HashMap<OwnedEventId, PduEvent> =
@@ -160,6 +173,33 @@ impl super::Service {
Ok(Some(state))
}
async fn fetch_state_ids_from_backfill_servers(
&self,
event_id: OwnedEventId,
room_id: OwnedRoomId,
) -> Result<get_room_state_ids::v1::Response> {
let candidates = self
.services
.timeline
.candidate_backfill_servers(&room_id)
.await;
debug!(%room_id, ?candidates, "Asking backfill servers for state_ids");
let futures = candidates.iter().map(|server_name| {
Box::pin(
self.services
.sending
.send_federation_request(
server_name,
get_room_state_ids::v1::Request::new(event_id.clone(), room_id.clone()),
)
.inspect_err(|e| {
debug_warn!("Fallback fetching state for event failed: {e}");
}),
)
});
Ok(select_ok(futures).await?.0)
}
/// Fetches the full state via `GET /_matrix/federation/v1/state` from a
/// remote server, and persists all the incoming auth chain events and
/// state events as outliers, for use later.