Skip to content

Guidance on custom implementations of coroutine dispatchers, and usage of Delay #3758

@martaciesielska

Description

@martaciesielska

I've been working on some code that uses a custom implementation of
CoroutineDispatcher for testing. Our test dispatcher uses fake time, and runs
everything on a single thread to ensure that tests are deterministic. It's not
appropriate for end-to-end testing but it works well with a lot of unit tests
(simplicity, speed, determinism). Due to the
inner workings of Kotlin coroutines,
we made our custom dispatcher implement the Delay interface to be able to
control scheduling, even though Delay is marked as
an internal API.

Additionally to the test dispatcher, we want to maintain a coroutine dispatcher
decorator that facilitates dispatch/suspension observability. This decorator
would look something like this:

internal class CoroutineDispatcherDecorator(
  private val delegate: CoroutineDispatcher,
  private val observer: Observer, // our interface for observing some events in the system
) : CoroutineDispatcher() {

  override fun dispatch(context: CoroutineContext, block: Runnable) {
    observer.onDispatch(context)
    delegate.dispatch(context) {
      try {
        block.run()
      } finally {
        observer.onSuspend(context)
      }
    }
  }
}

With this decorator, we run into another problem with Delay: if delegate
actually implements it, we hide it by using the decorator.

Given the above, I wanted to ask some questions:

  1. Are there any plans to make Delay public or provide some other public API
    in its place? I've seen
    one issue from 2020
    where it was actually recommended to someone to implement Delay, is this
    advice up-to-date? I understand that if we use Delay, we run the risk of our
    code getting broken with some future release of Kotlin coroutines.

  2. If not, are custom implementations of dispatchers discouraged? Neither
    CoroutineDispatcher nor ContinuationInterceptor are marked as internal so at
    first glance it seems like this is OK but not implementing Delay could lead to
    unexpected behaviour. Is there any guidance on this (I haven't found it in the
    documentation but maybe I've missed it)?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions