diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/autoimport/ExternalSystemProjectAware.kt b/platform/external-system-api/src/com/intellij/openapi/externalSystem/autoimport/ExternalSystemProjectAware.kt index 0efae8cfd634..ee205717d7c6 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/autoimport/ExternalSystemProjectAware.kt +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/autoimport/ExternalSystemProjectAware.kt @@ -5,6 +5,7 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.Event import com.intellij.openapi.externalSystem.autoimport.ExternalSystemSettingsFilesModificationContext.ReloadStatus import org.jetbrains.annotations.ApiStatus +import kotlin.time.Duration interface ExternalSystemProjectAware { @@ -21,6 +22,21 @@ interface ExternalSystemProjectAware { fun reloadProject(context: ExternalSystemProjectReloadContext) + /** + * Internal. Please see implementation limitations. + * + * This property defines a delay for the "smart" project sync request. + * Usually, the "smart" sync is requested after changes in the [settingsFiles]. + * + * Note: All external systems sync events are dispatched and merged by the same [com.intellij.util.ui.update.MergingUpdateQueue]. + * Therefore, this value can be overridden by the greater [smartProjectReloadDelay]. + * For example, between default (3 seconds) and zero delays will be chosen the default delay. + * + * A null value means default [smartProjectReloadDelay] that is equals to 3 seconds. + */ + @get:ApiStatus.Internal + val smartProjectReloadDelay: Duration? get() = null + /** * Experimental. Please see implementation limitations. * diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/autoimport/AutoImportProjectTracker.kt b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/autoimport/AutoImportProjectTracker.kt index 7d3a6a0bc25e..074848bbca93 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/autoimport/AutoImportProjectTracker.kt +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/autoimport/AutoImportProjectTracker.kt @@ -41,6 +41,13 @@ import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicReference import kotlin.streams.asStream +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds + +private val MERGING_TIME_SPAN = 300.milliseconds +private val MERGING_TIME_SPAN_MS = MERGING_TIME_SPAN.inWholeMilliseconds + +private val DEFAULT_SMART_PROJECT_RELOAD_DELAY = 3.seconds @ApiStatus.Internal @State(name = "ExternalSystemProjectTracker", storages = [Storage(CACHE_FILE)]) @@ -60,7 +67,7 @@ class AutoImportProjectTracker( private val projectChangeOperation = AtomicOperationTrace(name = "Project change operation") private val projectReloadOperation = AtomicOperationTrace(name = "Project reload operation") private val isProjectLookupActivateProperty = AtomicBooleanProperty(false) - private val dispatcher = MergingUpdateQueue("AutoImportProjectTracker.dispatcher", 300, true, null, serviceDisposable) + private val dispatcher = MergingUpdateQueue("AutoImportProjectTracker.dispatcher", MERGING_TIME_SPAN_MS.toInt(), true, null, serviceDisposable) private val backgroundExecutor = AppExecutorUtil.createBoundedApplicationPoolExecutor("AutoImportProjectTracker.backgroundExecutor", 1) private fun createProjectChangesListener() = @@ -103,17 +110,20 @@ class AutoImportProjectTracker( schedule(priority = 1, dispatchIterations = 1) { processChanges() } } - /** - * ``` - * dispatcher.mergingTimeSpan = 300 ms - * dispatchIterations = 9 - * We already dispatched processChanges - * So delay is equal to (1 + 9) * 300 ms = 3000 ms = 3 s - * ``` - */ private fun scheduleDelayedSmartProjectReload() { LOG.debug("Schedule delayed project reload") - schedule(priority = 2, dispatchIterations = 9) { reloadProject(explicitReload = false) } + + // See AutoImportProjectTracker.scheduleChangeProcessing for details + val smartProjectReloadDelay = projectDataMap.values.maxOfOrNull { + it.projectAware.smartProjectReloadDelay ?: DEFAULT_SMART_PROJECT_RELOAD_DELAY + } ?: DEFAULT_SMART_PROJECT_RELOAD_DELAY + // We already dispatched processChanges with the MERGING_TIME_SPAN delay + // See AutoImportProjectTracker.scheduleChangeProcessing for details + val smartProjectReloadDispatcherIterations = ((smartProjectReloadDelay - MERGING_TIME_SPAN) / MERGING_TIME_SPAN).toInt() + // smartProjectReloadDispatcherIterations can be negative if smartProjectReloadDelay is less than MERGING_TIME_SPAN + val dispatchIterations = maxOf(smartProjectReloadDispatcherIterations, 1) + + schedule(priority = 2, dispatchIterations = dispatchIterations) { reloadProject(explicitReload = false) } } private val currentActivity = AtomicReference()