Hi everyone,
I was studying the use of the @persist
decorator when applied at the class level versus the method level, but I’m still unclear on how state persistence actually works.
Let’s start with the class-level application.
After running the following example code — written purely to observe the effects of the decorator applied at different levels — it seems that applying @persist
at the class level has the following effect:
It saves the state of the flow every time a step (method) in the flow is successfully executed.
from crewai.flow.flow import Flow, listen, start, router
from crewai.flow.persistence import persist
from pydantic import BaseModel
class State(BaseModel):
counter: int = 0
@persist(verbose=True)
class FlowClassPersistance(Flow[State]):
@start()
def first(self):
print(f"Initial counter: {self.state.counter}")
print("Executing first method")
self.state.counter += 1
print(f"Counter: {self.state.counter}")
return
@listen(first)
def increase(self):
print("Executing increase method")
self.state.counter *= 2
print(f"Counter: {self.state.counter}")
if self.state.counter <= 2:
raise Exception("Stopping the flow due to error")
return "next"
@listen(increase)
def increase_next(self):
print("Executing increase_next method")
self.state.counter *= 2
print(f"Counter: {self.state.counter}")
return "next"
def main():
try:
flow = FlowClassPersistance()
flow1 = flow.kickoff()
print(f"Esecuzione 1, counter: {flow.state.counter}")
except Exception as e:
flow2 = flow.kickoff(inputs={
"id": flow.state.id, # Use the same ID to load the persisted state
})
print(f"Esecuzione 2, counter: {flow.state.counter}")
if __name__ == "__main__":
main()
Here’s the summary of the output I get:
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
└── 🧠 Starting Flow...
Flow started with ID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── 🧠 Starting Flow...
└── 🔄 Running: first
Initial counter: 0
Executing first method
Counter: 1
⚠️ #HERE, AFTER THE 'FIRST' METHOD HAS BEEN SUCCESSFULLY COMPLETED, THE STATE IS SAVED.
Saving flow state to memory for ID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
└── ✅ Completed: first
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
├── ✅ Completed: first
└── 🔄 Running: increase
Executing increase method
Counter: 2
⚠️# HERE, THE 'INCREASE' METHOD FAILED, SO THE STATE IS NOT SAVED.
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
├── ✅ Completed: first
└── ❌ Failed: increase
[Flow._execute_single_listener] Error in method increase: Stopping the flow due to error
⚠️#FLOW RE-EXECTUED PASSING THE STATE ID OF THE PREVIOUS FLOW
Loading flow state from memory for UUID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
└── 🧠 Starting Flow...
Flow started with ID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── 🧠 Starting Flow...
└── 🔄 Running: first
Initial counter: 1 ⚠️# STATE LOADED AS EXPECTED
Executing first method
Counter: 2
Saving flow state to memory for ID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
└── ✅ Completed: first
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
├── ✅ Completed: first
└── 🔄 Running: increase
Executing increase method
Counter: 4
Saving flow state to memory for ID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
├── ✅ Completed: first
└── ✅ Completed: increase
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
├── ✅ Completed: first
├── ✅ Completed: increase
└── 🔄 Running: increase_next
Executing increase_next method
Counter: 8
Saving flow state to memory for ID: 2054d94e-3164-409e-a5a4-821703d1297c
🌊 Flow: FlowClassPersistance
ID: 2054d94e-3164-409e-a5a4-821703d1297c
├── Flow Method Step
├── ✅ Completed: first
├── ✅ Completed: increase
└── ✅ Completed: increase_next
Moving on to method-level persistence, it’s not clear to me when the state is actually saved.
Here is the example code:
from crewai.flow.flow import Flow, listen, start, router
from crewai.flow.persistence import persist
from pydantic import BaseModel
class State(BaseModel):
counter: int = 0
class FlowMethodPersistence(Flow[State]):
@start()
def first(self):
print(f"Initial counter: {self.state.counter}")
print("Executing first method")
self.state.counter += 1
print(f"Counter: {self.state.counter}")
return
@listen(first)
def increase(self):
print("Executing increase method")
self.state.counter *= 2
print(f"Counter: {self.state.counter}")
if self.state.counter <= 2:
raise Exception("Stopping the flow due to error")
return "next"
@persist(verbose=True) # ⚠️I EXPECT THE STATE TO BE SAVED ONLY AFTER THIS METHOD IS EXECUTED SUCCESSFULLY.
@listen(increase)
def increase_next(self):
print("Executing increase_next method")
self.state.counter *= 2
print(f"Counter: {self.state.counter}")
return "next"
def main():
try:
flow = FlowMethodPersistence()
flow1 = flow.kickoff()
print(f"Esecuzione 1, valore del counter {flow.state.counter}")
except Exception as e:
flow2 = flow.kickoff(inputs={
"id": flow.state.id, # Use the same ID to load the persisted state
})
print(f"Esecuzione 2, valore del counter {flow.state.counter}")
if __name__ == "__main__":
main()
the output i get does not match what i expect; in fact, it seems the state is saved beforehand. here is the output i get:
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
└── 🧠 Starting Flow...
Flow started with ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── 🧠 Starting Flow...
└── 🔄 Running: first
Initial counter: 0
Executing first method
Counter: 1
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
└── ✅ Completed: first
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
├── ✅ Completed: first
└── 🔄 Running: increase
Executing increase method
Counter: 2
# ⚠️HERE THE METHOD FAILED, SO I EXPECT THE STATE NOT TO BE SAVED.
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
├── ✅ Completed: first
└── ❌ Failed: increase
[Flow._execute_single_listener] Error in method increase: Stopping the flow due to error
⚠️#FLOW RE-EXECTUED PASSING THE STATE ID OF THE PREVIOUS FLOW
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
└── 🧠 Starting Flow...
Flow started with ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── 🧠 Starting Flow...
└── 🔄 Running: first
#⚠️HERE I EXPECTED THE COUNTER TO BE 0.
Initial counter: 2
Executing first method
Counter: 3
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
└── ✅ Completed: first
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
├── ✅ Completed: first
└── 🔄 Running: increase
Executing increase method
Counter: 6
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
├── ✅ Completed: first
└── ✅ Completed: increase
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
├── ✅ Completed: first
├── ✅ Completed: increase
└── 🔄 Running: increase_next
Executing increase_next method
Counter: 12
Saving flow state to memory for ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
🌊 Flow: FlowMethodPersistence
ID: bd5ce9bf-2ec6-4caf-830a-9b2463af8efd
├── Flow Method Step
├── ✅ Completed: first
├── ✅ Completed: increase
└── ✅ Completed: increase_next
✅ Flow Finished: FlowMethodPersistence
├── Flow Method Step
├── ✅ Completed: first
├── ✅ Completed: increase
└── ✅ Completed: increase_next