The workflow state keeps track of the state of the workflow as it progresses. The state is stored in the configured persistence, and can be used to map incoming messages to handlers.
Defining the state
A workflow state is created by extending WorkflowState. The $name property should be unique among all of your workflows.
import { WorkflowState } from '@node-ts/bus-core'
export class FulfilmentWorkflowState extends WorkflowState {
static NAME = 'FulfilmentWorkflowState'
$name = FulfilmentWorkflowState.NAME
// Set of user-defined state properties
itemId: string
customerId: string
status: 'posting-item' | 'sending-receipt' | 'complete'
}
Accessing the state
The state is available as the second parameter to all handlers of a workflow. For example:
import { Workflow } from '@node-ts/bus-core'
export class FulfilmentWorkflow extends Workflow<FulfilmentWorkflowState> {
configureWorkflow (
mapper: WorkflowMapper<FulfilmentWorkflowState, FulfilmentWorkflow>
): void {
mapper
.withState(FulfilmentWorkflowState)
// ...
.when(ItemShipped, 'emailReceipt')
}
// Workflow state is passed in as the second parameter to a workflow handler
async emailReceipt (_: ItemShipped, state: FulfilmentWorkflowState) {
// ...
}
}
Updating the state
The state cannot be modified directly within a handling scope but can be updated by returning the intended changes from a handler. Returning an updated state is optional, and if omitted then no changes to the state will be persisted.
import { Workflow } from '@node-ts/bus-core'
export class FulfilmentWorkflow extends Workflow<FulfilmentWorkflowState> {
configureWorkflow (
mapper: WorkflowMapper<FulfilmentWorkflowState, FulfilmentWorkflow>
): void {
mapper
.withState(FulfilmentWorkflowState)
// ...
.when(ItemShipped, 'emailReceipt')
}
// Workflow state is passed in as the second parameter to a workflow handler
async emailReceipt (_: ItemShipped, state: FulfilmentWorkflowState) {
return { status: 'sending-receipt' }
}
}
Discarding state
There are times when the workflow data shouldn't persist after a message has been handled. This is particularly relevant in cases where a workflow should only handle a message under certain circumstances.
For example, if your workflow is started by an S3ObjectCreated event, but should only create a new workflow if the object key is prefixed with /documents, then this can be achieved by returning this.discardWorkflow() in the workflow like so:
import { Workflow, BusInstance } from '@node-ts/bus-core'
export class ProcessDocumentWorkflow extends Workflow<ProcessDocumentWorkflowState> {
constructor (bus: BusInstance) {}
configureWorkflow (
mapper: WorkflowMapper<ProcessDocumentWorkflowState, ProcessDocumentWorkflow>
): void {
mapper
.withState(ProcessDocumentWorkflowState)
.startedBy(S3ObjectCreated, 'readDocument')
}
async readDocument (event: S3ObjectCreated) {
if (event.s3Key.indexOf('/documents') === 0 {
await this.bus.send(new ReadDocument(event.s3Key))
} else {
// Ignore this message and avoid persisting the workflow state
return this.discardWorkflow()
}
}
}