Efficient State Machine Modeling Using FalkorDB

Picture of Roi Lipman
Roi Lipman
CTO & CO-Founder

Table of Contents

Share Articles
The latest release of FalkorDB V4.0.5 includes a new ability to easily clone graphs.

In this blog post we'll be developing a state machine framework where a machine is represented by a graph.

Whenever a FSM (finite state machine) is executed a copy of the initial graph is created and the execution is bound to that dedicated clone.

This approach is extremely flexible, as one can easily adjust a machine and changes will be applied to all future executions seamlessly, or in case a modification needs to be A/B tested a clone of the graph is easily made and compared to a baseline.

Let's get started, we'll create a simple machine which:

1. Download a source file
2. Count the number of lines in that file
3. Delete the file

State Machine Representation

Our graph representation of a state machine is a simple DAG (directed acyclic graph)
Nodes represent states, in each machine there’s a START state and an END state in addition to intermediate states.

Every state node contains the following attributes:

  • Cmd – the shell command to run
  • Description – short description of the state
  • Output – command output (available after execution)
  • ExitCode – command exit code (available after execution)

 

The states are connected to one another via a NEXT directed edge.

				
					# StateMachine
class StateMachine:
    def create_state(self, cmd, desc):
    def connect_states(self, src, dest):

# Create machine
machine = StateMachine("line_count")

# Create states
A = machine.create_state("curl -o graph.c https://raw.github.com/FalkorDB/FalkorDB/master/src/graph/graph.c", "download file")
B = machine.create_state("wc -l ./graph.c", "count lines")
C = machine.create_state("rm ./graph.c", "delete file")
 
# Connect steps
machine.connect_states(A, B)
machine.connect_states(B, C)
				
			
States
Pipeline

Running the State Machine

Once we’re ready to execute our FSM, a copy of the DAG is created, this is done automatically via the handy new GRAPH.COPY command, as we don’t want to taint our machine “template” with specific execution information.

The execution begins at the START state, our runner executes the state’s command, once the command completes the runner updates the states’s Output and ExitCode attributes and proceed to the next state, this process repeats itself until the last state is executed.

				
					# Run Machine
# clone machine
machine = self.clone()

print(f"Running machine {machine.name}")

# get first state
state = machine.initial_state()

# run state
while state is not None:
    machine.run_state(state)
    
    # get next state
    state = machine.next_state(state)

print(f"Finished running machine {machine.name}")
return machine
				
			

Output:

				
					Running machine line_count_2024-03-06 14:38:00.292751

Executing curl -o graph.c https://raw.githubusercontent.com/FalkorDB/FalkorDB/master/src/graph/graph.c
Output:

Executing wc -l ./graph.c
Output:     1426 ./graph.c

Executing rm ./graph.c
Output:

Finished running machine line_count_2024-03-06 14:38:00.292751
				
			

Conclusions

With very little effort we’ve been able to build a simple state machine system, which takes advantage of a number of FalkorDB unique features:

  • the ability to store, maintain and switch effortlessly between thousandths of different graphs
  • our new feature to quickly create copies of graphs
 
The source code of this demo is available on Github.
 
Continuing with this demo we would love to explore an integration with one of the already established FSM frameworks, it’s our belief that FalkorDB can be an interesting backend for such systems.

Related Articles

code-visualization-featured-image

Code Visualization: Benefits, Best Practices & Popular Tools

Modern software architectures are complex systems of interconnected components. As projects grow, keeping track of all their moving parts becomes increasingly challenging. Complex control flows, deeply nested structures, and…
Diagram showing Hypothetical Document Embeddings where a query is processed by an LLM to generate an answer, which is then used to find the best matching document chunk, leading to a final response.

Advanced RAG Techniques: What They Are & How to Use Them

Retrieval-Augmented Generation (RAG) has become a mainstream approach for working with large language models (LLMs) since its introduction in early research. At its core, RAG gathers knowledge from various…
The Future of Graph Databases

Welcome to FalkorDB – The Future of Graph Databases

At FalkorDB, we are redefining the boundaries of what’s possible with graph databases. Our advanced, ultra-low latency solution is designed to empower your data-driven applications with unparalleled performance, scalability,…