Skip to content

Commit

Permalink
[docs] Add kstatemachine-coroutines artifact documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
nsk90 committed Jul 25, 2024
1 parent 1902656 commit 80e942a
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 18 deletions.
75 changes: 75 additions & 0 deletions docs/pages/coroutines_artifact.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
layout: page
title: Coroutines artifact
---

# Coroutines artifact

{: .no_toc }

## Page contents

{: .no_toc .text-delta }

- TOC
{:toc}

This page contains information about `kstatemachine-coroutines` artifact functionality.
Which contains the library APIs for working in `Kotlin Coroutines` environment.

> This artifact depends on Kotlin Coroutines library
You can find common information about multithreading library usage and coroutines on
[multithreading page](https://kstatemachine.github.io/kstatemachine/pages/multithreading.html)

## Artifact separation

`KStateMachine` has first class support of coroutines. Even if you don't use `Kotlin Coroutines`
and `kstatemachine-coroutines` artifact all library callbacks are `suspendable` functions.
So the functionality of this module should not be treated as "wrappers" or "extensions".
This is just a core functionality which is separated from original `kstatemachine` artifact
to fallow language architecture regarding coroutines support.

Contains additional functions to work with KStateMachine depending on Kotlin Coroutines library

## State machine creation

The artifact contains `createStateMachine()` / `createStateMachineBlocking()` methods, which were described in
[Create state machine](https://kstatemachine.github.io/kstatemachine/pages/statemachine.html#create-state-machine)
block

## Flow notifications

Coroutines users often use `Flow` to get some changes from a source.
The library provides `StateMachine` extension methods which represents notification APIs (listeners) in a form of `Flow`:

* `stateMachineNotificationFlow()` returns a `SharedFlow` of all machine notifications:

```kotlin
machine.stateMachineNotificationFlow().collect {
when (it) {
is Started -> println("Started ${it.machine}")
is TransitionTriggered -> println("TransitionTriggered ${it.transitionParams.event}")
is TransitionComplete -> println("TransitionComplete ${it.transitionParams.event}")
is StateEntry -> println("StateEntry ${it.state}")
is StateExit -> println("StateExit ${it.state}")
is StateFinished -> println("StateFinished ${it.state}")
is Stopped -> println("Stopped ${it.machine}")
is Destroyed -> println("Destroyed ${it.machine}")
}
}
```

* `activeStatesFlow()` returns a `StateFlow` of active machine states:

```kotlin
machine.activeStatesFlow().collect { activeStates ->
println("The set of active states: $activeStates")
}
```

## Event processing

`processEventByLaunch()` and `processEventByAsync()` functions are described in
[event processing](https://kstatemachine.github.io/kstatemachine/pages/events.html#event-processing) block.
You can use them to process events in asynchronous way.
12 changes: 6 additions & 6 deletions docs/pages/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ Generally it is not recommended to confuse them with commands, see [do not secti
When a StateMachine is created, configured and started it is ready to process incoming events.
It is done with `processEvent()` functions family.

* `processEvent()` - suspendable version
* `processEventBlocking()` - blocking version. Not suspendable, uses `kotlinx.coroutines.runBlocking`
* `processEvent()` - suspendable version, synchronous
* `processEventBlocking()` - blocking version. Not suspendable, synchronous. Uses `kotlinx.coroutines.runBlocking`
internally if you use StateMachine with coroutines support. Or just runs code in-place for StdLib StateMachine
instance.
* `processEventByLaunch()` - (available in `kstatemachine-coroutines` artifact) Not suspendable, uses StateMachine's
`CouroutineScope` to process event in a new coroutine by `kotlinx.coroutines.launch` function.
* `processEventByLaunch()` - (available in `kstatemachine-coroutines` artifact) Not suspendable, asynchronous, uses
StateMachine's `CouroutineScope` to process event in a new coroutine by `kotlinx.coroutines.launch` function.
Cannot be used with StdLib StateMachine instance (throws in this case).
* `processEventByAsync()` - (available in `kstatemachine-coroutines` artifact) Not suspendable, uses StateMachine's
`CouroutineScope` to process event in a new coroutine by `kotlinx.coroutines.async` function.
* `processEventByAsync()` - (available in `kstatemachine-coroutines` artifact) Not suspendable, asynchronous, uses
StateMachine's `CouroutineScope` to process event in a new coroutine by `kotlinx.coroutines.async` function.
Returns`kotlinx.coroutines.Deffered` with `ProcessingResult`.
Cannot be used with StdLib StateMachine instance (throws in this case).

Expand Down
12 changes: 2 additions & 10 deletions docs/pages/multithreading.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Many functions like `createStateMachine`/`start`/`stop`/`processEvent`/`undo` et
has analogs with `Blocking` suffix which are not marked with `suspend` keyword.
If you use KStateMachine with coroutines support you should prefer suspendable function versions.
Note that `Blocking` versions internally use `kotlinx.coroutines.runBlocking` function which is rather dangerous and
may cause deadlocks if used not properly. That is why you should avoid using `Blocking` APIs from coroutines and
recursively (from library callbacks).
may cause deadlocks if used not properly (especially recursively).
That is why you should avoid using `Blocking` APIs from coroutines and recursively (from library callbacks).

### Use single threaded `CoroutineScope`

Expand Down Expand Up @@ -110,14 +110,6 @@ runBlocking { // defines non-empty coroutine context for state machine
}
```

## Additional kstatemachine-coroutines artifact

Contains additional functions to work with KStateMachine depending on Kotlin Coroutines library

* `createStateMachine()` / `createStateMachineBlocking()` creates state machine with specified `CoroutineScope`
* `stateMachineNotificationFlow()` returns a `SharedFlow` of all machine notifications
* `activeStatesFlow()` returns a `StateFlow` of active machine states

## Migration guide from versions older than v0.20.0

### If you already have or ready to add Kotlin Coroutines dependency
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/statemachine.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ nav_order: 1

A state machine can be created with one of those factory functions:

* `createStateMachine()` suspendable version (from `kstatemachine-coroutines` artifact)
* `createStateMachine()` suspendable version (from `kstatemachine-coroutines` artifact), the best choice by default.
* `createStateMachineBlocking()` blocking version (from `kstatemachine-coroutines` artifact)
* `createStdLibStateMachine()` - creates StateMachine instance without Kotlin Coroutines support
(from `kstatemachine` artifact)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ fun createTestStateMachine(
init = init
)
CoroutineStarterType.COROUTINES_LIB_SINGLE_THREAD_DISPATCHER -> createStateMachineBlocking(
CoroutineScope(newSingleThreadContext("test single thread context")),
CoroutineScope(newSingleThreadContext("test single thread context")), // fixme context leaks
name,
childMode,
start,
Expand Down

0 comments on commit 80e942a

Please sign in to comment.