fix: use correct cancellation checks in suspend functions

isActive is a CoroutineScope extension and has no CoroutineScope
receiver in plain suspend fun bodies (runSync, downloadFromRelay).

- runSync catch block: split into CancellationException (rethrow) +
  Exception, removing the invalid isActive guard entirely
- downloadFromRelay while loop: while(isActive) -> while(true) with
  coroutineContext.ensureActive() as the first statement, which works
  in any suspend fun and throws CancellationException when cancelled

The isActive import is kept for the supervisorScope lambda in
downloadFromPool, where a CoroutineScope receiver is in scope.

https://claude.ai/code/session_01U8qF9mK4UBvXsXP1zNMXfX
This commit is contained in:
Claude
2026-03-14 15:03:45 +00:00
parent 5905926d4a
commit 666c795c93
@@ -33,6 +33,8 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.supervisorScope
@@ -237,10 +239,10 @@ class EventSyncViewModel(
totalEventsSent = totalSent.get().toInt(),
durationMs = System.currentTimeMillis() - startTime,
)
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
if (isActive) {
_syncState.value = SyncState.Error(e.message ?: "Unknown error")
}
_syncState.value = SyncState.Error(e.message ?: "Unknown error")
}
}
@@ -287,7 +289,8 @@ class EventSyncViewModel(
) {
var until: Long? = null
while (isActive) {
while (true) {
coroutineContext.ensureActive()
val pageCount = AtomicInteger(0)
val pageMinTs = AtomicLong(Long.MAX_VALUE)
val done = Channel<Unit>(Channel.CONFLATED)