-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace WorkflowHost with a static runWorkflow function #439
Comments
I started to implement this, but the API for cancelling the runtime from within the block feels very awkward. It stops the runtime, but causes the I'm starting to think For main-based apps, |
Note to self for implementation: // Result participates in job hierarchy so it will automatically get cancelled if the runtime
// is cancelled externally (so that finishWorkflow will return false).
val resultDeferred = CompletableDeferred<T>(parent = coroutineContext[Job])
launch {
val workflowJob = coroutineScope[Job]!!
fun finishWorkflow(result: T): Boolean {
workflowJob.cancel(CancellationException("Workflow finished normally"))
return resultDeferred.complete(result)
}
val workflowScope = WorkflowScope(this, ::finishWork)
beforeSetup(workflowScope, renderings, outputs)
// Yield to allow any coroutines created by beforeSetup to collect the flows to start.
// This means that collection will start before the runtime, even if launch(UNDISPATCHED) is not used.
yield()
// Run loop
}
return resultDeferred.await() |
Also, we forgot the snapshot parameter. So the actual function signature we need is: suspend fun <InputT, OutputT : Any, RenderingT, ResultT> runWorkflow(
workflow: Workflow<InputT, OutputT, RenderingT>,
inputs: Flow<InputT>,
initialSnapshot: Snapshot? = null,
beforeStart: WorkflowScope<ResultT>.(
renderingsAndSnapshots: Flow<RenderingAndSnapshot<RenderingT>>,
outputs: Flow<OutputT>
) -> Unit
): ResultT where interface WorkflowScope<in ResultT> : CoroutineScope {
fun finishWorkflow(result: ResultT): Boolean
} I am also wondering if we have any uses where we're not supplying interface WorkflowScope<in InputT, in ResultT> : CoroutineScope {
fun setInput(input: InputT)
fun finishWorkflow(result: ResultT): Boolean
}
suspend fun <InputT, OutputT : Any, RenderingT, ResultT> runWorkflow(
workflow: Workflow<InputT, OutputT, RenderingT>,
initialInput: InputT,
initialSnapshot: Snapshot? = null,
beforeStart: WorkflowScope<InputT, ResultT>.(
renderingsAndSnapshots: Flow<RenderingAndSnapshot<RenderingT>>,
outputs: Flow<OutputT>
) -> Unit
): ResultT
We could even make |
Probably useful (internally at least) to have: inline fun <R> WorkflowScope(
coroutineScope: CoroutineScope,
crossinline finishWorkflow: (R) -> Boolean
): WorkflowScope<R> = object : WorkflowScope<R>, CoroutineScope by coroutineScope {
override fun finishWorkflow(result: R): Boolean = finishWorkflow(result)
} |
And for #389: fun <I, O> runWorkflowOutputs(
workflow: Workflow<I, O, *>,
inputs: Flow<I>
): Flow<O> = channelFlow {
runWorkflow(workflow, inputs) { _, outputs ->
outputs.onEach(::send)
.launchIn(this)
}
}
// Don't have a use case for this without renderings, but it's even simpler.
suspend fun <I, O> runWorkflowUntilFirstOutput(
workflow: Workflow<I, O, *>,
inputs: Flow<I>
): O = runWorkflow(workflow, inputs) { _, outputs ->
outputs.onEach { finishWorkflow(it) }
.launchIn(this)
} Note there's no initial snapshot because there's no way to read snapshots. We could also do one for renderings: fun <I, R> runWorkflowRenderings(
workflow: Workflow<I, *, R>,
inputs: Flow<I>,
initialSnapshot: suspend () -> Snapshot?
): Flow<RenderingAndSnapshot<R>> = channelFlow {
runWorkflow(workflow, inputs, initialSnapshot()) { renderings, _ ->
renderings.onEach(::send)
.launchIn(this)
}
} Note that |
WorkflowHost.Factory
isn't useful, andWorkflowHost.start
isn't quite idiomatic. Instead:Note that block does not
suspend
. It is a setup function. The workflow is not started until block exits.runWorkflow
blocks forever, since workflows have no way to end themselves.The text was updated successfully, but these errors were encountered: