mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
[find in files] IJPL-186012 Improve RPC reliability and module state handling
- Add RpcCallUtil with retry mechanism for handling RPC timeouts - Refactor ModuleUpdatedEvent to use map-based approach for batch module operations - Streamline ModulesStateService initialization and event subscription GitOrigin-RevId: 6847e95107abc3776f2e8a706a5d840d31ab00d0
This commit is contained in:
committed by
intellij-monorepo-bot
parent
cbc828ab48
commit
3fa289a400
@@ -52,7 +52,7 @@ internal class FindRemoteApiImpl : FindRemoteApi {
|
||||
return@coroutineScope
|
||||
}
|
||||
val filesToScanInitially = filesToScanInitially.mapNotNull { it.virtualFile() }.toSet()
|
||||
//TODO there should be read action in case of the loading from a directory
|
||||
//read action is necessary in case of the loading from a directory
|
||||
val scope = readAction { FindInProjectUtil.getGlobalSearchScope(project, findModel) }
|
||||
FindInProjectUtil.findUsages(findModel, project, progressIndicator, presentation, filesToScanInitially) { usageInfo ->
|
||||
val virtualFile = usageInfo.virtualFile
|
||||
|
||||
@@ -17,6 +17,7 @@ jvm_library(
|
||||
"//platform/editor-ui-api:editor-ui",
|
||||
"//platform/core-ui",
|
||||
"//platform/usageView",
|
||||
"//fleet/rpc",
|
||||
]
|
||||
)
|
||||
### auto-generated section `build intellij.platform.ide.rpc` end
|
||||
@@ -0,0 +1,3 @@
|
||||
f:com.intellij.ide.rpc.RpcCallUtil
|
||||
- sf:INSTANCE:com.intellij.ide.rpc.RpcCallUtil
|
||||
- f:invokeSafely(kotlin.jvm.functions.Function1,kotlin.coroutines.Continuation):java.lang.Object
|
||||
|
||||
@@ -39,5 +39,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.editor.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.usageView" />
|
||||
<orderEntry type="module" module-name="fleet.rpc" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.rpc
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import fleet.rpc.client.RpcTimeoutException
|
||||
|
||||
private val log = Logger.getInstance(RpcCallUtil::class.java)
|
||||
object RpcCallUtil {
|
||||
|
||||
suspend fun <T> invokeSafely(rpcCall: suspend () -> T): T {
|
||||
var attempt = 0
|
||||
while (true) {
|
||||
try {
|
||||
return rpcCall.invoke()
|
||||
}
|
||||
catch (_: RpcTimeoutException) {
|
||||
attempt++
|
||||
log.error("RPC call timed out. (attempt $attempt)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,9 @@ import com.intellij.platform.rpc.backend.RemoteApiProvider
|
||||
import com.intellij.util.Function
|
||||
import fleet.rpc.remoteApiDescriptor
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -24,32 +25,33 @@ internal class ModuleStateApiImpl : ModuleStateApi {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override suspend fun getModulesUpdateEvents(projectId: ProjectId): Flow<ModuleUpdatedEvent> {
|
||||
val project = projectId.findProjectOrNull() ?: return emptyFlow()
|
||||
val flow = MutableSharedFlow<ModuleUpdatedEvent>()
|
||||
val connection = project.messageBus.simpleConnect()
|
||||
val connection = project.messageBus.simpleConnect()
|
||||
val flow = channelFlow {
|
||||
val coroutineScope = ModulesStateService.getInstance(project).coroutineScope
|
||||
connection.subscribe(ModuleListener.TOPIC, object : ModuleListener {
|
||||
override fun modulesAdded(project: Project, modules: List<Module>) {
|
||||
coroutineScope.launch {
|
||||
for (module in modules) {
|
||||
flow.emit(ModuleUpdatedEvent(ModuleUpdateType.ADD, module.name))
|
||||
}
|
||||
send(ModuleUpdatedEvent(ModuleUpdateType.ADD, modules.map { it.name}))
|
||||
}
|
||||
}
|
||||
|
||||
override fun moduleRemoved(project: Project, module: Module) {
|
||||
coroutineScope.launch {
|
||||
flow.emit(ModuleUpdatedEvent(ModuleUpdateType.REMOVE, module.name))
|
||||
send(ModuleUpdatedEvent(ModuleUpdateType.REMOVE, module.name))
|
||||
}
|
||||
}
|
||||
|
||||
override fun modulesRenamed(project: Project, modules: List<Module>, oldNameProvider: Function<in Module, String>) {
|
||||
coroutineScope.launch {
|
||||
modules.forEach { module ->
|
||||
flow.emit(ModuleUpdatedEvent(ModuleUpdateType.RENAME, oldNameProvider.`fun`(module), module.name))
|
||||
}
|
||||
send(ModuleUpdatedEvent(ModuleUpdateType.RENAME, modules.associate { module ->
|
||||
module.name to oldNameProvider.`fun`(module)
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
awaitClose { connection.disconnect() }
|
||||
}
|
||||
return flow
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ jvm_library(
|
||||
"//platform/util",
|
||||
"//platform/projectModel-api:projectModel",
|
||||
"//platform/util/coroutines",
|
||||
"//platform/platform-impl/rpc",
|
||||
],
|
||||
runtime_deps = [":project_resources"]
|
||||
)
|
||||
|
||||
@@ -3,6 +3,5 @@ f:com.intellij.platform.project.module.ModulesStateService
|
||||
- f:getCoroutineScope():kotlinx.coroutines.CoroutineScope
|
||||
- sf:getInstance(com.intellij.openapi.project.Project):com.intellij.platform.project.module.ModulesStateService
|
||||
- f:getModuleNames():java.util.Set
|
||||
- f:getProject():com.intellij.openapi.project.Project
|
||||
f:com.intellij.platform.project.module.ModulesStateService$Companion
|
||||
- f:getInstance(com.intellij.openapi.project.Project):com.intellij.platform.project.module.ModulesStateService
|
||||
|
||||
@@ -41,5 +41,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.util" />
|
||||
<orderEntry type="module" module-name="intellij.platform.projectModel" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.coroutines" />
|
||||
<orderEntry type="module" module-name="intellij.platform.ide.rpc" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -33,4 +33,9 @@ enum class ModuleUpdateType {
|
||||
|
||||
@Internal
|
||||
@Serializable
|
||||
open class ModuleUpdatedEvent(val moduleUpdateType: ModuleUpdateType, val moduleName: String, val newModuleName: String = moduleName)
|
||||
class ModuleUpdatedEvent(val moduleUpdateType: ModuleUpdateType, val newToOldModuleNameMap: Map<String, String>){// val moduleName: String, val newModuleName: String = moduleName) {
|
||||
constructor(moduleUpdateType: ModuleUpdateType, moduleNames: List<String>) : this(moduleUpdateType, moduleNames.associateWith { it })
|
||||
constructor(moduleUpdateType: ModuleUpdateType, moduleName: String) : this(moduleUpdateType, mapOf(moduleName to moduleName))
|
||||
|
||||
val moduleNames: Set<String> = newToOldModuleNameMap.keys
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.platform.project.module
|
||||
|
||||
import com.intellij.ide.rpc.RpcCallUtil
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
@@ -16,13 +17,12 @@ import kotlinx.coroutines.launch
|
||||
private val LOG = logger<ModulesStateService>()
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
class ModulesStateService private constructor(val project: Project, val coroutineScope: CoroutineScope) {
|
||||
class ModulesStateService private constructor(private val project: Project, val coroutineScope: CoroutineScope) {
|
||||
private val state: ModulesState = ModulesState()
|
||||
private var initializationCompleted: Boolean = false
|
||||
|
||||
init {
|
||||
val initialJob = loadInitialModuleNames()
|
||||
subscribeToModuleChanges(initialJob)
|
||||
loadModuleNamesAndSubscribe()
|
||||
}
|
||||
|
||||
fun getModuleNames(): Set<String> {
|
||||
@@ -33,24 +33,22 @@ class ModulesStateService private constructor(val project: Project, val coroutin
|
||||
return state.moduleNames
|
||||
}
|
||||
|
||||
private fun loadInitialModuleNames(): Job {
|
||||
return coroutineScope.childScope("ModulesStateService.loadInitialModuleNames").launch {
|
||||
LOG.debug("Starting initial module names loading for project: ${project.name}\n")
|
||||
val moduleNames = ModuleStateApi.getInstance().getCurrentModuleNames(project.projectId())
|
||||
private fun loadModuleNamesAndSubscribe(): Job {
|
||||
return coroutineScope.childScope("ModulesStateService.loadModuleNamesAndSubscribe").launch {
|
||||
LOG.debug("Starting initial module names loading for project: ${project.name}")
|
||||
val moduleNames = RpcCallUtil.invokeSafely { ModuleStateApi.getInstance().getCurrentModuleNames(project.projectId()) }
|
||||
state.moduleNames.addAll(moduleNames.toMutableSet())
|
||||
LOG.debug("Completed loading initial module names. Found ${moduleNames.size} modules")
|
||||
initializationCompleted = true
|
||||
subscribeToModuleChanges()
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToModuleChanges(initialJob: Job) {
|
||||
coroutineScope.childScope("ModulesStateService.subscribeToModuleChanges").launch {
|
||||
initialJob.join()
|
||||
LOG.debug("Starting subscription for module updates in project: ${project.name}")
|
||||
ModuleStateApi.getInstance().getModulesUpdateEvents(project.projectId()).collect { update ->
|
||||
LOG.debug("Received module update: $update")
|
||||
state.applyModuleChange(update)
|
||||
}
|
||||
private suspend fun subscribeToModuleChanges() {
|
||||
LOG.debug("Starting subscription for module updates in project: ${project.name}")
|
||||
RpcCallUtil.invokeSafely { ModuleStateApi.getInstance().getModulesUpdateEvents(project.projectId()) }.collect { update ->
|
||||
LOG.debug("Received module update: $update")
|
||||
state.applyModuleChange(update)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +66,13 @@ private class ModulesState() {
|
||||
fun applyModuleChange(moduleUpdatedEvent: ModuleUpdatedEvent) {
|
||||
when (moduleUpdatedEvent.moduleUpdateType) {
|
||||
ModuleUpdateType.RENAME -> {
|
||||
moduleNames.remove(moduleUpdatedEvent.moduleName)
|
||||
moduleNames.add(moduleUpdatedEvent.newModuleName)
|
||||
moduleUpdatedEvent.newToOldModuleNameMap.forEach { (newName, oldName) ->
|
||||
moduleNames.remove(oldName)
|
||||
moduleNames.add(newName)
|
||||
}
|
||||
}
|
||||
ModuleUpdateType.ADD -> moduleNames.add(moduleUpdatedEvent.moduleName)
|
||||
ModuleUpdateType.REMOVE -> moduleNames.remove(moduleUpdatedEvent.moduleName)
|
||||
ModuleUpdateType.ADD -> moduleNames.addAll(moduleUpdatedEvent.moduleNames)
|
||||
ModuleUpdateType.REMOVE -> moduleNames.removeAll(moduleUpdatedEvent.moduleNames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user