9.9 KiB
Execution Contexts
Tracking execution progress, checking for cancellations, and switching between different execution contexts.
The IntelliJ Platform provides APIs that allow tracking the progress of background processes and canceling their execution when they are canceled by a user, or they become obsolete due to some changes in the data model.
Background processes can be executed in three contexts:
Currently, the Progress Indicator context is the most widely used approach in the IntelliJ Platform. As the platform's execution model moves towards coroutines, this approach can be considered obsolete. Starting with 2024.1, it is recommended to execute new code in the suspending context.
The following sections explain the contexts and provide information about process cancellation, progress tracking, and switching between different contexts.
Suspending Context (Coroutines)
Code executed in Kotlin coroutines is executed in a suspending context. Since 2024.1, this context is recommended for executing background tasks to maximize CPU utilization.
Note that executing code in a suspending context is possible only with Kotlin.
{style="warning"}
In a suspending context, methods such as ProgressManager.checkCanceled()
or ModalityState.defaultModalityState()
won't have any effect.
Therefore, if their behavior is required, switch to a blocking context.
Inspection Plugin DevKit | Code | Forbidden in suspend context method usage reports calling blocking code from suspending context.
Blocking Context
Executing tasks in a blocking context means executing them on a thread without access to the coroutine context (basically, in non-suspending functions) and not under a progress indicator. Such tasks can't be canceled by using coroutines' or progress indicator's cancellation capabilities, which may block threads and consume resources even if the task is no longer relevant.
Usually, plugins should not execute new code in the blocking context. Always prefer executing tasks in the suspending context or under the progress indicator if a plugin cannot use Kotlin.
Functions which schedule execution via
Application.executeOnPooledThread()
and similar methods, and which rely onProgressManager.checkCanceled()
should be annotated with@RequiresBlockingContext
to inform clients about the required switch to a blocking context.Inspection Plugin DevKit | Code | Calling method should be annotated with @RequiresBlockingContext reports missing annotations.
Progress Indicator
Code executed via the Progress API
(ProgressManager
,
ProgressIndicator
, etc.)
is executed in a progress indicator context.
See the section for details.
Executing code under the progress indicator is obsolete since 2024.1. It is advised to use Kotlin coroutines in new code.
Please note that obsolete status does not mean deprecation. Executing code using the Progress API is still allowed, but coroutines are recommended as a more performant solution.
{style="tip" title="Obsolete approach since 2024.1"}
Execution Contexts APIs
Cancellation Check
The following table presents APIs to use for checking whether a task was canceled in different execution contexts.
Suspending |
ensureActive() from Kotlin coroutine's API
Note that ProgressManager.checkCanceled() does not work in a suspending context.
|
Blocking |
ProgressManager.checkCanceled()
See Background Processes: Cancellation for details. |
Progress Indicator |
ProgressIndicator.checkCanceled() , ProgressManager.checkCanceled()
See Background Processes: Cancellation for details. |
Progress Reporting
The following table presents the possibilities and APIs to use for reporting progress in different execution contexts.
Suspending |
Any |
Blocking | unavailable |
Progress Indicator |
ProgressIndicator 's or ProgressManager 's methods
See Background Processes: Tracking Progress for details. |
Switching Between Contexts
The following table presents the possibilities and APIs to use for switching between different execution contexts.
To Suspending | To Blocking | To Progress Indicator | |
From Suspending | - | blockingContext() 1 |
unavailable 3 |
From Blocking | runBlockingCancellable() 2 |
- | unavailable 4 |
From Progress Indicator | runBlockingCancellable() 2 |
unavailable | - |
1 blockingContext() enables ProgressManager.checkCanceled() , forwards modality state, etc. It has an opposite behavior to runBlockingCancellable() .2 runBlockingCancellable() has an opposite behavior to blockingContext() 3 coroutineToIndicator() is an internal API to aid platform migration4 blockingContextToIndicator() is an internal API to aid platform migration
|
It is only possible to:
- switch from the blocking context or progress indicator to the suspending context
- switch from the suspending context to the blocking context
The lack of an API for switching from suspending and blocking contexts to progress indicator is intentional. Cancellable and trackable tasks should be run in coroutines as the progress indicator is obsolete since 2024.1.