Possible to Implement Finite State Machine using Workflows?

Im trying to see if temporal Workflows are conceptually equivalent to Finite State Machines.
If this analogy is correct, where are the state variables ?
Will it be the Input and Output to the @WorkflowMethod ?
or will it be the attributes of @WorkflowInstance implementing class ?

Or maybe Workflows cannot be thought of as being a part of an FSM ?

Thoughts ?

Would recommend reading this blog: Designing A Workflow Engine from First Principles | Temporal documentation

Read the link.
( But it is only about implementing the temporal Engine itself )
I was asking about implementing a business FSM using Temporal.
Can we consider each @WorkflowMethod as a state transition logic ?
( But if we do, where is teh state itself being stored, which can be accessed by the next state transition logic )

Maybe, a single @WorkflowMethod should be thought of as containing multiple state transition logics?
( In other words, a single workflow should be considered as implementing the complete FSM with its multiple state transitions ā€¦instead of implementing different workflows for each state transition )
Something like

class MyWorkflowInterfaceImpl implements WorkflowInterface {
    State state ;

    //@WorkflowMethod
    Output myWorkflowmethod( Input ip ) {
	state = getStartState(ip ) ; // Start state -> state1
	//some *non* activity code that changes state -> state transition1 -> state2
	//activity1 -> state transition2 -> state3
	//some *non* activity code that does *not* changes state -> no state tranition -> still state3
	//activity2 -> state transition2 -> state4
	
    }
}

The whole workflow execution state can be thought as a state machine. The workflow object + local variables + thread stack being the state. But we recommend just implementing your business logic through code without thinking about state machines. There are some cases when modeling workflow logic as a state machine is applicable, but these are pretty rare.

What is the problem you are trying to solve?

Thank you very much Maxim.
( It is clear now )
We are not trying to solve any new problem. Im just trying to learn Temporal for our new project.
( For our problem, thinking of Workflows as business code - like you suggested - is good enough )

Thank you again.

ā€“sony

Have a similar problem, an external API is used to get state of object workflow is tracking, and workflow periodically calls it and compare previous state and new state then perform action base on that.

I think local variables in workflow definition are persisted, but do you have a pointer on how? Want to make sure the way I use it does not result in state loss.

Thanks!

While currentState.IsClosed() {
nextState = getExternalState()
workflow.ExecuteActivity(ctx, PerformAction, currentState).Get(ctx, nextState)
currentState = nextState;
timer.sleep(1h);
}

What is getExternalState?

just a API call to get metadata of from another service

Direct calls to other services is prohibited from the workflow code as it can break determinism.

Will wrapping the API call in an activity or changing to block on an external signal make it deterministic?

Also wonder how is workflow local variable like current state get persisted?

Local variables are not persisted.
It creates that illusion.
Activities and other service calls are really proxies, whose calls are recorded
Input to a workflow is also recorded.
When a workflow is recovered, it instantiates the Workflow object first and then calls the workflow method passing the input as parameter ( It has stored the input in history )
Each time it hits a proxy, it checks the history to see if this call has already been made. If the call has been made, then it is bypassed. This goes on till it hits a proxy that has not been called yet, at which point workflow is ā€œresumedā€

This is called ā€˜Event Sourcingā€™ Pattern

A side effect is that, if in the beginning of the workflow, you have a CPU intense part, when the workflow is resumed, the CPU intense part will be played again although you have already done that before the crash.

Local variables are not persisted.
It creates that illusion.

I think we should be careful here. From the user point of view, local variables are durable, so they are ā€œpersistedā€. What @sonyantony described is the mechanism that is used to persist them.

My scenario is to use workflow to track object state from another service. I was thinking to keep pulling external object state(or have the external service signal about object state transition) and keep prev state and current state to determine state transition so that I can perform actions based on the transitions.

As there is loop in external object state transition(state 1 can to go 2 then go back to 1), I am thinking about using a while loop and only terminate when external service tell me the object is in terminate state.

From the event sourcing pattern described, I think if I can while loop the workflow and move state local variable based on signal(external service call temporal client to trigger state move), since all signal will be recorded, my workflow should be resilient? @maxim

The trick is to not think about ā€œevent sourcingā€ while writing workflows. It is just a mechanism used to restore the state. So when you write a workflow just assume that all of the workflow state is durable.

So having a loop that updates the state variable is a reasonable pattern. Something like:

  while(!state.isFinal()) {
      Workflow.await(() -> signalData != null);
      state.apply(signalData);
      signalData = null;
  }
1 Like

So you have a workflow and an external ( not temporal ) serviceā€¦ external service is what goes through state transitionsā€¦temporal qorkflow is there just to track the external service.

Is this the correct understanding of your situation?

If yes, then making the external service send a signal to the workflow whenever it changes state will avoid not only unnecessary polling but also will eliminate the lag between polling interval

Thanks, that is what I thought, and keep pulling is not deterministic thus will result in losing states.

keep pulling is not deterministic thus will result in losing states.

I donā€™t understand what you said here. It is absolutely OK to implement polling from an activity.

He was saying that if the external system changes back to the original state before the next poll, his workflow will fail to reflect a state change

Temporal Workflow in loop = WF

Poll from WF ( fetches state A)ā€¦state changes to Bā€¦State changes back to Aā€¦poll from WF( fetches state A)

What about the external system failing to send the signal before the external system changes back to the original state? If missing state transitions is important it doesnā€™t really matter if push or pull is used. It has to remember and return the history of state transitions in any case.

Also, it is not linked to determinism in any way.

Doesnā€™t signals break deterministic behavior always ?

If there is a crash, and when the qorkflow gets restored, will it replay receiving the signal also if there was a signal before the crash ?