From 386b467d118139bc39f1d4b0403b215fc2c8ebe6 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Thu, 14 May 2026 18:35:23 +0530 Subject: [PATCH 1/3] fix: close indexing services on background thread Signed-off-by: Akash Yadav --- .../service/IndexingServiceManager.kt | 37 +++++++++++++++---- .../androidide/projects/ProjectManagerImpl.kt | 1 - 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt b/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt index 3a5b98de66..87eef28dda 100644 --- a/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt +++ b/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt @@ -4,10 +4,14 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeout +import kotlinx.coroutines.withTimeoutOrNull import org.slf4j.LoggerFactory import java.io.Closeable import java.util.concurrent.ConcurrentHashMap +import kotlin.time.Duration.Companion.seconds /** * Manages the lifecycle of [IndexingService]s and the [IndexRegistry]. @@ -20,6 +24,9 @@ class IndexingServiceManager( companion object { private val log = LoggerFactory.getLogger(IndexingServiceManager::class.java) + + /** The timeout duration for closing indexing services */ + private val SERVICE_CLOSE_TIMEOUT = 10.seconds } /** @@ -116,19 +123,33 @@ class IndexingServiceManager( override fun close() { log.info("Shutting down indexing services") - // Cancel in-flight work - scope.coroutineContext.cancelChildren() // Close services in reverse registration order - services.values.reversed().forEach { service -> - try { - service.close() - log.debug("Closed service: {}", service.id) - } catch (e: Exception) { - log.error("Failed to close service: {}", service.id, e) + val cancellationJobs = services.values.reversed().map { service -> + scope.launch(Dispatchers.Default) { + withTimeoutOrNull(SERVICE_CLOSE_TIMEOUT) { + try { + service.close() + log.debug("Closed service: {}", service.id) + } catch (e: Exception) { + log.error("Failed to close service: {}", service.id, e) + } + } ?: run { + log.warn("Indexing service {} failed to close within timeout period: {}ms", service.id, SERVICE_CLOSE_TIMEOUT.inWholeMilliseconds) + } } } + scope.launch { + runCatching { joinAll(*cancellationJobs.toTypedArray()) } + .onFailure { err -> + log.error("Failed to close indexing services", err) + } + + // Cancel in-flight work + scope.coroutineContext.cancelChildren() + } + services.clear() registry.close() initialized = false diff --git a/subprojects/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt b/subprojects/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt index 357fda6b78..69be62d785 100644 --- a/subprojects/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt +++ b/subprojects/projects/src/main/java/com/itsaky/androidide/projects/ProjectManagerImpl.kt @@ -53,7 +53,6 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.toList import kotlinx.coroutines.withContext -import org.appdevforall.codeonthego.indexing.service.IndexingService import org.appdevforall.codeonthego.indexing.service.IndexingServiceManager import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe From 61d3861f77e72b1b40cf083d04bb196820cad580 Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Thu, 14 May 2026 18:44:49 +0530 Subject: [PATCH 2/3] fix: rethrow cancellation exceptions when closing indexing services Signed-off-by: Akash Yadav --- .../codeonthego/indexing/service/IndexingServiceManager.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt b/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt index 87eef28dda..3d72f908b7 100644 --- a/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt +++ b/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt @@ -1,5 +1,6 @@ package org.appdevforall.codeonthego.indexing.service +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -132,6 +133,7 @@ class IndexingServiceManager( service.close() log.debug("Closed service: {}", service.id) } catch (e: Exception) { + if (e is CancellationException) throw e log.error("Failed to close service: {}", service.id, e) } } ?: run { From 7b25a0d5286779e944be657e04439473031c83bb Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Thu, 14 May 2026 19:05:17 +0530 Subject: [PATCH 3/3] fix: close index registry on background thread Signed-off-by: Akash Yadav --- .../service/IndexingServiceManager.kt | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt b/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt index 3d72f908b7..61f6af2d31 100644 --- a/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt +++ b/lsp/indexing/src/main/kotlin/org/appdevforall/codeonthego/indexing/service/IndexingServiceManager.kt @@ -7,7 +7,6 @@ import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.joinAll import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeoutOrNull import org.slf4j.LoggerFactory import java.io.Closeable @@ -142,8 +141,21 @@ class IndexingServiceManager( } } + val closeRegistryJob = scope.launch(Dispatchers.Default) { + withTimeoutOrNull(SERVICE_CLOSE_TIMEOUT) { + try { + registry.close() + } catch (e: Exception) { + if (e is CancellationException) throw e + log.error("Failed to close index registry") + } + } ?: run { + log.warn("Index registry failed to close within timeout: {}ms", SERVICE_CLOSE_TIMEOUT.inWholeMilliseconds) + } + } + scope.launch { - runCatching { joinAll(*cancellationJobs.toTypedArray()) } + runCatching { joinAll(closeRegistryJob, *cancellationJobs.toTypedArray()) } .onFailure { err -> log.error("Failed to close indexing services", err) } @@ -153,10 +165,9 @@ class IndexingServiceManager( } services.clear() - registry.close() initialized = false - log.info("Indexing services shut down") + log.info("Indexing services shut down requested") } private suspend fun initializeServices() {