From bb0713b686ec05a2679238e2cd40d4b4ca1ee101 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Sat, 8 Aug 2026 11:34:02 +0300 Subject: [PATCH] Fix tracing span panic when accessed from multiple threads Brings it in sync with the TimelineItemProvider as it happens. --- .../RoomSummary/RoomSummaryProvider.swift | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift index 0f3924271..74431a5cd 100644 --- a/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift +++ b/ElementX/Sources/Services/Room/RoomSummary/RoomSummaryProvider.swift @@ -238,12 +238,6 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { on currentRooms: [RoomSummary], eventStringBuilder: RoomEventStringBuilder, name: String) async -> [RoomSummary] { - let span = MXLog.createSpan("\(name).process_room_list_diffs") - span.enter() - defer { - span.exit() - } - var updatedRooms = currentRooms for diff in diffs { updatedRooms = await processDiff(diff, on: updatedRooms, eventStringBuilder: eventStringBuilder, name: name) @@ -257,6 +251,15 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { return currentItems } + // The span guard is thread local, so it must not straddle a suspension + // point, otherwise the task could resume on a different thread and + // unbalance it, causing a panic and subsequent (intentional) crash. + let span = MXLog.createSpan("\(name).apply_room_list_diff") + span.enter() + defer { + span.exit() + } + guard let updatedItems = currentItems.applying(collectionDiff) else { MXLog.error("\(name): Failed applying diff: \(collectionDiff)") return currentItems @@ -447,19 +450,13 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol { private func rebuildRoomSummaries() async { MXLog.info("\(name): Rebuilding room summaries for \(rooms.count) rooms") - rooms = await Self.rebuiltRoomSummaries(from: rooms, eventStringBuilder: eventStringBuilder, name: name) + rooms = await Self.rebuiltRoomSummaries(from: rooms, eventStringBuilder: eventStringBuilder) MXLog.info("\(name): Finished rebuilding room summaries (\(rooms.count) rooms)") } @concurrent - private static func rebuiltRoomSummaries(from rooms: [RoomSummary], eventStringBuilder: RoomEventStringBuilder, name: String) async -> [RoomSummary] { - let span = MXLog.createSpan("\(name).rebuild_room_summaries") - span.enter() - defer { - span.exit() - } - + private static func rebuiltRoomSummaries(from rooms: [RoomSummary], eventStringBuilder: RoomEventStringBuilder) async -> [RoomSummary] { var rebuiltRooms = [RoomSummary]() rebuiltRooms.reserveCapacity(rooms.count) for room in rooms {