fix(coroutines): propagate cancellation in remote source and status view model

RemoteSource's five suspend functions and SatStatusViewModel's two fetch paths
caught bare Exception, which also swallows CancellationException. When the
owning scope is cancelled (screen leaves, app closes) a cancelled network call
was reported as a null/error result instead of stopping: the caller kept
running until the next suspension point, and SatStatusViewModel wrote state
updates into an already-cancelled scope. Correct coroutine hygiene is to let
cancellation propagate - rethrow CancellationException before the generic
catch. Verified semantically with an asyncio probe: a swallowed cancel returns
a normal-looking null and the caller continues; a propagated cancel stops the
coroutine immediately.

No behaviour change for real errors; :core:data and :feature:status compile.
This commit is contained in:
mckero committed 2026-08-17 16:46:09 +00:00
1 parent baf2a7022d
commit 7319cf8f5b
2 files changed
+16

No files matched your search

@@ -20,6 +20,7 @@ package com.rtbishop.look4sat.core.data.source
import android.content.ContentResolver
import androidx.core.net.toUri
import com.rtbishop.look4sat.core.domain.source.IRemoteSource
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
@@ -37,6 +38,8 @@ class RemoteSource(
try {
val fileUri = uri.toUri()
contentResolver.openInputStream(fileUri)?.buffered()
} catch (exception: CancellationException) {
throw exception
} catch (exception: Exception) {
println("RemoteSource file stream exception: $exception")
null
@@ -53,6 +56,8 @@ class RemoteSource(
if (!response.isSuccessful) return@use null
response.body?.string()
}
} catch (exception: CancellationException) {
throw exception
} catch (exception: Exception) {
println("RemoteSource amsat status exception: $exception")
null
@@ -66,6 +71,8 @@ class RemoteSource(
if (!response.isSuccessful) return@withContext null
ByteArrayInputStream(response.body.bytes())
}
} catch (exception: CancellationException) {
throw exception
} catch (exception: Exception) {
println("RemoteSource network stream exception: $exception")
null
@@ -82,6 +89,8 @@ class RemoteSource(
if (!response.isSuccessful) return@use null
response.body?.string()
}
} catch (exception: CancellationException) {
throw exception
} catch (exception: Exception) {
println("RemoteSource amsat catalog exception: $exception")
null
@@ -98,6 +107,8 @@ class RemoteSource(
if (!response.isSuccessful) return@use null
response.body?.string()
}
} catch (exception: CancellationException) {
throw exception
} catch (exception: Exception) {
println("RemoteSource amsat reports exception: $exception")
null