Worker

interface Worker<out OutputT>(source)

Represents a unit of asynchronous work that can have zero, one, or multiple outputs.

Workers allow you to execute arbitrary, possibly asynchronous tasks in a declarative manner. To perform their tasks, workers return a Flow. Workers are effectively Flows that can be compared to determine equivalence between render passes. A Workflow uses Workers to perform asynchronous work during the render pass by calling BaseRenderContext.runningWorker.

See the documentation on run for more information on the returned Flow is consumed and how to implement asynchronous work.

See the documentation on doesSameWorkAs for more details on how and when workers are compared and the worker lifecycle.

Example: Network request

Let's say you have a network service with an API that returns a number, and you want to call that service from a Workflow.

interface TimeService {
suspend fun getTime(timezone: String): Long
}

The first step is to define a Worker that can call this service, and maybe an extension function on your service class:

fun TimeService.getTimeWorker(timezone: String): Worker<Long> = TimeWorker(timezone, this)

private class TimeWorker(
val timezone: String,
val service: TimeService
): Worker<Long> {

override fun run(): Flow<Long> = flow {
val time = service.getTime(timezone)
emit(time)
}
}

You also need to define how to determine if a previous Worker is already doing the same work. This will ensure that if the same request is made by the same Workflow in adjacent render passes, we'll keep the request alive from the first pass.

override fun doesSameWorkAs(otherWorker: Worker<*>): Boolean =
otherWorker is TimeWorker &&
timezone == otherWorker.timezone

Now you can request the time from your Workflow:

class MyWorkflow(private val timeWorker: TimeWorker) {
override fun render(…): Foo {
context.runningWorker(timeWorker) { time -> emitOutput("The time is $time") }
}

Alternatively, if the response is a unique type, unlikely to be shared by any other workers, you don't even need to create your own Worker class, you can use a builder, and the worker will automatically be distinguished by that response type:

interface TimeService {
fun getTime(timezone: String): Deferred<TimeResponse>
}

fun TimeService.getTimeWorker(timezone: String): Worker<TimeResponse> =
Worker.from { getTime(timezone).await()) }

See also

Inheritors

Types

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
open fun doesSameWorkAs(otherWorker: Worker<*>): Boolean

Override this method to define equivalence between Workers. The default implementation returns true if this worker's class is the same as otherWorker's class.

Link copied to clipboard
abstract fun run(): Flow<OutputT>

Returns a Flow to execute the work represented by this worker.

Link copied to clipboard
fun <T, R> Worker<T>.transform(transform: (Flow<T>) -> Flow<R>): Worker<R>

Returns a Worker that transforms this Worker's Flow by calling transform.