Skip to content
Ocean-Atlasv0.1.0Canonical Knowledge

In-Memory FSM

A service needs stateful, mode-dependent behavior for the lifetime of a session or a single logical flow — for example, a calculator whose next operation depends on which mode it is currently in — but that state has no independent persisted identity worth storing in a database.

How do you model behavior that depends on “which mode am I in” without persisting a database entity purely to hold a status field?

  • Consistency — state must still change only through defined transitions, even without a database backing it.
  • Reuse — the same event and state vocabulary as an entity-backed FSM should stay usable, so behavior can move to persistence later without a redesign.
  • Complexity — entry and exit hooks and validation still need a defined place to run.
  • Persistence — explicitly out of scope: state resets between instances or deployments unless mirrored elsewhere.

Declare an @fsm with in-memory instead of controls <Entity>.<field>, list its states and default state directly, and use on enter, on exit, and on event blocks the same way an entity-backed FSM would. Pair it with a service-local @context for values that should survive across events within the same session, such as the last computed mode.

stateDiagram-v2
[*] --> NoOp
NoOp --> Adding: setOperation(add)
NoOp --> Subtracting: setOperation(sub)
Adding --> NoOp: setOperation(nop)
Subtracting --> NoOp: setOperation(nop)
Adding --> Adding: calculate
Subtracting --> Subtracting: calculate
@context
CalcFsmContext
mode : String (default=no operation)
@fsm
CalcFSM in-memory
states : NoOp, Adding, Subtracting
default : NoOp
event setOperation in(op:String) out(result:String)
event calculate in(a:Float & b:Float) out(r:Float)
use context CalcFsmContext as fsmCtx
use expression CalcAdd as add
use expression CalcSub as sub
state Every
on event setOperation : logic
if op == "add" then
next Adding : result = "ADD"
end
next NoOp
state NoOp
on enter : logic
update fsmCtx.mode = "No-operation mode."
on event calculate : logic
emit r = 0
state Adding
on enter:
update fsmCtx.mode = "Adding mode."
on event calculate:
emit r = add(a, b)

This is a minimal illustrative fragment, not a complete duplicated example — see Working Examples for the full, runnable model.

  • No database or entity overhead for behavior that is genuinely transient.
  • The same event and transition vocabulary as Entity-Backed FSM keeps the two patterns easy to move between as requirements change.
  • A service-local context gives a small amount of state that survives across events without persistence.
  • State does not survive a process restart or move across instances unless explicitly synchronized elsewhere.
  • Not appropriate once the behavior needs to be queried, audited, or resumed by identity outside the current session.
  • If the modeled behavior must be queryable, auditable, or resumed by identity across sessions, use Entity-Backed FSM instead.
  • In-Memory Calculator FSM — an in-memory FSM whose active state selects calculator behavior and updates shared context.
  • Entity-Backed FSM — the alternative when the behavior does have a persisted identity to control.