diff --git a/android/app/src/main/java/com/fabledsword/minstrel/diagnostics/DiagnosticsUploader.kt b/android/app/src/main/java/com/fabledsword/minstrel/diagnostics/DiagnosticsUploader.kt index 6ed816b2..b4be91c6 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/diagnostics/DiagnosticsUploader.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/diagnostics/DiagnosticsUploader.kt @@ -70,8 +70,10 @@ class DiagnosticsUploader @Inject constructor( /** Coalesces concurrent triggers via tryLock — a drain in flight wins. */ private suspend fun drainSafe() { - if (authStore.sessionCookie.value.isNullOrEmpty()) return - val clientId = authStore.clientId.value ?: return + val clientId = authStore.clientId.value + // Signed out / no client id yet → nothing to do. Single guard keeps + // the return count within the detekt gate. + if (authStore.sessionCookie.value.isNullOrEmpty() || clientId == null) return if (!mutex.tryLock()) return try { drain(clientId) @@ -81,13 +83,14 @@ class DiagnosticsUploader @Inject constructor( } private suspend fun drain(clientId: String) { - while (true) { + var more = true + while (more) { val batch = runCatching { dao.takeBatch(BATCH_SIZE) }.getOrNull().orEmpty() - if (batch.isEmpty()) return - val sent = runCatching { upload(clientId, batch) }.isSuccess - if (!sent) return // leave rows for the next trigger - runCatching { dao.deleteByIds(batch.map { it.id }) } - if (batch.size < BATCH_SIZE) return + val sent = batch.isNotEmpty() && runCatching { upload(clientId, batch) }.isSuccess + if (sent) runCatching { dao.deleteByIds(batch.map { it.id }) } + // Keep going only while a full batch sent cleanly; otherwise stop + // (empty buffer, or a failure to retry on the next trigger). + more = sent && batch.size >= BATCH_SIZE } }