Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public fun <PropsT, StateT, OutputT, ChildRenderingT>
* Ensures a [Worker] that never emits anything is running. Since [worker] can't emit anything,
* it can't trigger any [WorkflowAction]s.
*
* A simple way to create workers that don't output anything is using [Worker.createSideEffect].
* If your [Worker] does not output anything, then simply use [runningSideEffect].
*
* @param key An optional string key that is used to distinguish between identical [Worker]s.
*/
Expand Down
15 changes: 13 additions & 2 deletions workflow-core/src/main/java/com/squareup/workflow1/Worker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public interface Worker<out OutputT> {
* Shorthand for `flow { block() }.asWorker()`.
*
* Note: If your worker just needs to perform side effects and doesn't need to emit anything,
* use [createSideEffect] instead (since `Nothing` can't be used as a reified type parameter).
* do not use a [Worker] but instead call [BaseRenderContext::runningSideEffect]
*/
@OptIn(ExperimentalTypeInference::class)
public inline fun <reified OutputT> create(
Expand All @@ -193,14 +193,25 @@ public interface Worker<out OutputT> {
* fun logOnEntered(message: String) = Worker.createSideEffect() {
* println("Entered state: $message")
* }
* ```
*
* Note that all workers created with this method are equivalent from the point of view of
* their [Worker.doesSameWorkAs] methods. A workflow that needs multiple simultaneous
* side effects can either bundle them all together into a single `createSideEffect`
* call, or can use the `key` parameter to [BaseRenderContext.runningWorker] to prevent
* conflicts.
* ```
*
* Deprecated: This convenience extension is deprecated as redundant.
* [BaseRenderContext.runningSideEffect] can be used instead with a suspend function
* and a key to uniquely identify the side effect in the runtime.
*/
@Deprecated(
message = "Worker not needed, simply call RenderContext.runningSideEffect " +
"with a suspend fun.",
ReplaceWith(
expression = "runningSideEffect(key, block)"
)
)
public fun createSideEffect(
block: suspend () -> Unit
): Worker<Nothing> = TypedWorker(TYPE_OF_NOTHING, flow { block() })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,11 +364,11 @@ class RenderWorkflowInTest {
@Test fun `cancelling scope cancels runtime`() {
var cancellationException: Throwable? = null
val workflow = Workflow.stateless<Unit, Nothing, Unit> {
runningWorker(Worker.createSideEffect {
runningSideEffect(key = "test1") {
suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { cause -> cancellationException = cause }
}
})
}
}
renderWorkflowIn(workflow, expectedSuccessScope, MutableStateFlow(Unit)) {}
assertNull(cancellationException)
Expand All @@ -383,11 +383,11 @@ class RenderWorkflowInTest {
@Test fun `failing scope cancels runtime`() {
var cancellationException: Throwable? = null
val workflow = Workflow.stateless<Unit, Nothing, Unit> {
runningWorker(Worker.createSideEffect {
runningSideEffect(key = "failing") {
suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { cause -> cancellationException = cause }
}
})
}
}
renderWorkflowIn(workflow, expectedSuccessScope, MutableStateFlow(Unit)) {}
assertNull(cancellationException)
Expand Down Expand Up @@ -418,13 +418,13 @@ class RenderWorkflowInTest {
@Test fun `error from renderings collector cancels runtime`() {
var cancellationException: Throwable? = null
val workflow = Workflow.stateless<Unit, Nothing, Unit> {
runningWorker(Worker.createSideEffect {
runningSideEffect(key = "test") {
suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { cause ->
cancellationException = cause
}
}
})
}
}
val renderings = renderWorkflowIn(workflow, allowedToFailScope, MutableStateFlow(Unit)) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,11 @@ internal class WorkflowRunnerTest {
@Test fun `cancelRuntime() cancels runtime`() {
var cancellationException: Throwable? = null
val workflow = Workflow.stateless<Unit, Nothing, Unit> {
runningWorker(Worker.createSideEffect {
runningSideEffect(key = "test side effect") {
suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { cause -> cancellationException = cause }
}
})
}
}
val runner = WorkflowRunner(workflow, MutableStateFlow(Unit))
runner.nextRendering()
Expand Down Expand Up @@ -209,11 +209,11 @@ internal class WorkflowRunnerTest {
@Test fun `cancelling scope cancels runtime`() {
var cancellationException: Throwable? = null
val workflow = Workflow.stateless<Unit, Nothing, Unit> {
runningWorker(Worker.createSideEffect {
runningSideEffect(key = "test") {
suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { cause -> cancellationException = cause }
}
})
}
}
val runner = WorkflowRunner(workflow, MutableStateFlow(Unit))
runner.nextRendering()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,8 @@ public inline fun <reified T : Any> Single<out T?>.asWorker(): Worker<T> =
*
* The key is required for this operator because there is no type information available to
* distinguish workers.
*
* TODO: https://github.com/square/workflow-kotlin/issues/526 once this is removed.
*/
@Suppress("DEPRECATION")
public fun Completable.asWorker(): Worker<Nothing> = Worker.createSideEffect { await() }
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ internal class WorkerCompositionIntegrationTest {

@Test fun `runningWorker gets error`() {
val workflow = Workflow.stateless<Unit, Unit, Unit> {
runningWorker(Worker.createSideEffect { throw ExpectedException() })
runningWorker(Worker.from<Unit> { throw ExpectedException() }) {
action { }
}
}

assertFailsWith<ExpectedException> {
Expand All @@ -156,8 +158,8 @@ internal class WorkerCompositionIntegrationTest {
val channel = Channel<Unit>()
val workflow = Workflow.stateless<Unit, Unit, Unit> {
runningWorker(
channel.consumeAsFlow()
.asWorker()
channel.consumeAsFlow()
.asWorker()
) { fail("Expected handler to not be invoked.") }
}

Expand All @@ -180,26 +182,26 @@ internal class WorkerCompositionIntegrationTest {
}

val workflow = Workflow.stateful<Int, Int, () -> Unit>(
initialState = 0,
render = { state ->
runningWorker(triggerOutput) { action { setOutput(state) } }
initialState = 0,
render = { state ->
runningWorker(triggerOutput) { action { setOutput(state) } }

return@stateful { actionSink.send(incrementState) }
}
return@stateful { actionSink.send(incrementState) }
}
)

workflow.launchForTestingFromStartWith {
triggerOutput.send(Unit)
assertEquals(0, awaitNextOutput())

awaitNextRendering()
.invoke()
.invoke()
triggerOutput.send(Unit)

assertEquals(1, awaitNextOutput())

awaitNextRendering()
.invoke()
.invoke()
triggerOutput.send(Unit)

assertEquals(2, awaitNextOutput())
Expand All @@ -223,9 +225,11 @@ internal class WorkerCompositionIntegrationTest {

@Test fun `runningWorker doesn't throw when worker finishes`() {
// No-op worker, completes immediately.
val worker = Worker.createSideEffect {}
val worker = Worker.from { }
val workflow = Workflow.stateless<Unit, Unit, Unit> {
runningWorker(worker)
runningWorker(worker) {
action { }
}
}

workflow.launchForTestingFromStartWith {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class WorkerTest {
}
}

@Suppress("DEPRECATION")
@Test fun `createSideEffect returns equivalent workers`() {
val worker1 = Worker.createSideEffect {}
val worker2 = Worker.createSideEffect {}
Expand All @@ -52,6 +53,7 @@ class WorkerTest {
assertTrue(worker1.doesSameWorkAs(worker2))
}

@Suppress("DEPRECATION")
@Test fun `createSideEffect runs`() {
var ran = false
val worker = Worker.createSideEffect {
Expand All @@ -63,6 +65,7 @@ class WorkerTest {
}
}

@Suppress("DEPRECATION")
@Test fun `createSideEffect finishes`() {
val worker = Worker.createSideEffect {}

Expand All @@ -71,6 +74,7 @@ class WorkerTest {
}
}

@Suppress("DEPRECATION")
@Test fun `createSideEffect propagates exceptions`() {
val worker = Worker.createSideEffect { throw ExpectedException() }

Expand Down
Loading