Merge pull request #7901 from element-hq/feature/bma/mainThreadBlocking

Avoid blocking the main thread in several places
This commit is contained in:
Benoit Marty
2026-10-14 16:39:14 +02:00
committed by GitHub
13 changed files with 117 additions and 74 deletions
@@ -118,6 +118,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapNotNull
@@ -320,7 +321,7 @@ class RustMatrixClient(
override fun onUpdate(profile: UserProfile) {
val matrixUser = profile.map()
_userProfile.tryEmit(matrixUser)
sessionCoroutineScope.launch {
sessionCoroutineScope.launch(sessionDispatcher) {
storeUserProfile(matrixUser)
}
}
@@ -1013,6 +1014,8 @@ class RustMatrixClient(
searchBackfillService.cancelPeriodicSearchBackfill()
}
}
// Checking the pending work is a blocking call, do not do it on the main thread
.flowOn(sessionDispatcher)
.launchIn(sessionCoroutineScope)
}
}
@@ -158,6 +158,7 @@ class JoinedRustRoom(
inner = innerRoom.threadListService(),
contentMapper = TimelineEventContentMapper(),
roomCoroutineScope = roomCoroutineScope,
roomDispatcher = roomDispatcher,
)
override val syncUpdateFlow = flow {
@@ -17,10 +17,12 @@ import io.element.android.libraries.matrix.api.room.threads.ThreadsListService
import io.element.android.libraries.matrix.impl.timeline.item.event.TimelineEventContentMapper
import io.element.android.libraries.matrix.impl.timeline.item.event.map
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
@@ -33,6 +35,7 @@ import org.matrix.rustcomponents.sdk.ThreadListService as InnerThreadListService
class RustThreadsListService(
private val inner: InnerThreadListService,
private val roomCoroutineScope: CoroutineScope,
private val roomDispatcher: CoroutineDispatcher,
private val contentMapper: TimelineEventContentMapper = TimelineEventContentMapper(),
) : ThreadsListService {
private var itemSubscriptionJob: Job? = null
@@ -63,6 +66,8 @@ class RustThreadsListService(
updated.apply(diff, contentMapper)
items.value = updated
}
// Fetching and mapping the items can be costly, do not do it on the main thread
.flowOn(roomDispatcher)
.launchIn(roomCoroutineScope)
}
@@ -33,7 +33,9 @@ import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.matrix.rustcomponents.sdk.Client
@@ -41,6 +43,7 @@ import org.matrix.rustcomponents.sdk.ClientDelegate
import java.io.File
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
@OptIn(ExperimentalCoroutinesApi::class)
class RustMatrixClientFactoryTest {
@Test
fun test() = runTest {
@@ -51,6 +54,7 @@ class RustMatrixClientFactoryTest {
val result = sut.create(aSessionData())
assertThat(result.sessionId).isEqualTo(SessionId("@alice:server.org"))
runCurrent()
// 2 workers are scheduled: one for the search backfill and one for the vacuum
scheduleWorkersLambda.assertions().isCalledExactly(2)
result.destroy()
@@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.test.A_TIMESTAMP
import io.element.android.libraries.matrix.test.A_USER_ID
import io.element.android.tests.testutils.lambda.lambdaRecorder
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -122,6 +123,7 @@ class RustThreadsListServiceTest {
) = RustThreadsListService(
inner = inner,
roomCoroutineScope = backgroundScope,
roomDispatcher = StandardTestDispatcher(testScheduler),
)
private fun aRustThreadListUpdate() = ThreadListUpdate.Append(