Runtimes
WorkflowRuntime
is responsible for the following tasks:
- Managing workflow state
- Persisting events
- Recovering state from events
- Waking up the workflow at the right moments
Each runtime is created per workflow type, and its creation usually involves implementation-specific elements.
WorkflowRuntime
interface allows creating a WorkflowInstance
based on id and input.
trait WorkflowRuntime[F[_], Ctx <: WorkflowContext, WorkflowId, Input] {
def createInstance(id: WorkflowId, input: Input): F[WorkflowInstance[F, WCState[Ctx]]]
}
Available Runtimes
Below is an overview of the available runtimes, with their strengths and limitations:
Runtime | Description | Good For | Bad For |
---|---|---|---|
PekkoRuntime | Uses Pekko Persistance and Cluster Sharding to manage the state and distribution of workload. |
|
|
DatabaseRuntime | Relies on database storage and locking mechanisms, without any in-memory state management. |
|
|
InMemoryRuntime | Based on Cats Effect; keeps state in memory without persistence. |
|
|
InMemorySyncRuntime | Vanilla Scala implementation, not thread-safe and lacks persistence. |
|
|
WorkflowEngine
Each WorkflowRuntime
is parameterized by a WorkflowInstanceEngine
,
a component that proxies all interactions between the instance and its state, allowing for plugging-in custom behaviours.
Below is an example of building an engine.
val knockerUpper: KnockerUpper.Agent = ???
val registry: WorkflowRegistry.Agent = ???
val engine: WorkflowInstanceEngine = WorkflowInstanceEngine.builder
.withJavaTime()
.withWakeUps(knockerUpper)
.withRegistering(registry)
.withGreedyEvaluation
.withLogging
.get
KnockerUpper
KnockerUpper
is a component responsible for waking up the workflow when needed, e.g., after timer has expired or retry is due.
See Wake-Ups for additional details.
WorkflowRegistry
WorkflowRegistry
is a component responsible for tracking the execution status of workflow instances.
See Collecting Instances for additional details.