IntelliJ Platform Plugin SDK Help

Coroutine Read Actions

The concept of read/write locks and running blocking and cancellable read actions is explained in the Threading section:

This section explains running read actions (RA) in coroutines specifically.

Coroutine Read Actions API

Running RA from coroutines is executed with *ReadAction* functions from coroutines.kt (see their KDocs for the details). Functions can be divided into two groups, which differ in reacting to an incoming write action (WA):

Write Allowing Read Action (WARA)

Write Blocking Read Action (WBRA)

readAction

readActionBlocking

smartReadAction

smartReadActionBlocking

constrainedReadAction

constrainedReadActionBlocking

WARA is canceled when a parent coroutine is canceled or a WA arrives.

WBRA is canceled only when a parent coroutine is canceled. It blocks WA until finishing its lambda.

Write Allowing Read Action vs. NonBlockingReadAction

WARA API is simpler than NonBlockingReadAction (NBRA). WARA doesn't need the following API methods:

  • submit(Executor backgroundThreadExecutor) because this is a responsibility of the coroutine dispatcher

  • executeSynchronously() because effectively they are executed in the current coroutine dispatcher already

  • expireWhen(BooleanSupplier expireCondition)/expireWith(Disposable parentDisposable)/wrapProgress(ProgressIndicator progressIndicator) because they are canceled when the calling coroutine is canceled

  • finishOnUiThread() because this is handled by switching to the EDT dispatcher. Note that the UI data must be pure (e.g., strings/icons/element pointers), which inherently cannot be invalidated during the transfer from a background thread to EDT.

  • coalesceBy(Object ... equality) because this should be handled by Flow.collectLatest() and/or Flow.distinctUntilChanged(). Usually, NBRAs are run as a reaction to user actions, and there might be multiple NBRAs running, even if their results are unused. Instead of cancelling the read action, in the coroutine world the coroutines are canceled:

    eventFlow.collectLatest { event -> // the next emitted event will cancel the current coroutine // and run it again with the next event readAction { readData() } } eventFlow.distinctUntilChanged().collectLatest { event -> // the next emitted event will cancel the current coroutine // and run it again with the next event if the next event // was not equal to the previous one readAction { readData() } }

Read Action Cancellability

Suspending read actions use coroutines as the underlying framework.

WARA (invoked with mentioned *ReadAction functions) may make several attempts to execute its lambda. The block needs to know whether the current attempt was canceled. *ReadAction functions create a child Job for each attempt, and this job becomes canceled when a write action arrives. *ReadAction restarts the block if it was canceled by a write action, or throws CancellationException if the calling coroutine was canceled, causing the cancellation of the child Job.

To check whether the current action was canceled, clients must call ProgressManager.checkCanceled(), which was adjusted to work in coroutines. Clients must not throw ProcessCanceledException manually.

Last modified: 10 April 2024