|
1 | 1 | ## Flow versioning (checkpointing) |
2 | 2 |
|
3 | | -Langflow uses `FlowVersion` to store immutable checkpoints of flow edits. |
| 3 | +Langflow uses `FlowVersion` to store snapshots of flow edits. |
4 | 4 |
|
5 | | -When you mutate a flow (especially `Flow.data`, `Flow.name`, `Flow.description`), you must also create a checkpoint in the **same database session/transaction** as the flow update. |
| 5 | +When you mutate a flow (particularly `Flow.data`), you must use `save_flow_checkpoint`. This function handles both the checkpoint creation (if `Flow.data` changes) and the update of the Flow object in the database. |
6 | 6 |
|
7 | 7 | ### Required |
8 | | -**ALWAYS call `save_flow_checkpoint` BEFORE updating the database object.** |
| 8 | +**ALWAYS use `save_flow_checkpoint` to update flow data.** |
| 9 | +`save_flow_checkpoint` updates the Flow row in the database and creates a new checkpoint (if needed) in the FlowVersion table in a single transaction. |
9 | 10 |
|
10 | | -`save_flow_checkpoint` works by comparing the *new data* you pass it against the *current data* in the database. If you update the database object first, the "old" data is lost (or the session sees the new data as the current data), and no change will be detected. |
| 11 | +`save_flow_checkpoint` compares the `update_data` you pass it against the *current data* in the database. It will: |
| 12 | +1. Fetch the current flow from the database. |
| 13 | +2. Compare the new data against the stored data. |
| 14 | +3. If `Flow.data` (the graph) has changed, create a new `FlowVersion` entry. |
| 15 | +4. Update the `Flow` object with the new values from `update_data`. |
| 16 | +5. Return the updated `Flow` object. |
11 | 17 |
|
12 | 18 | ### Example: Updating a Flow |
13 | 19 |
|
14 | 20 | #### ✅ DO THIS |
15 | | -Create the checkpoint *before* applying changes to the DB object. |
| 21 | +Pass the session (optional), user ID, flow ID, and the dictionary of updates to `save_flow_checkpoint`. |
16 | 22 |
|
17 | 23 | ```python |
18 | | -# 1. Prepare your new data |
19 | | -new_flow_data = {...} |
20 | | -flow_update = FlowUpdate(data=new_flow_data) |
21 | | - |
22 | | -# 2. Checkpoint FIRST (compares new_flow_data vs DB state) |
23 | | -await save_flow_checkpoint( |
| 24 | +# 1. Prepare your new data (e.g. from a FlowUpdate model) |
| 25 | +# update_data = flow_update.model_dump(exclude_unset=True, exclude_none=True) |
| 26 | +update_data = {"data": {...}, "name": "New Name", "description": "New Desc"} |
| 27 | + |
| 28 | +# 2. Checkpoint and Update |
| 29 | +# save_flow_checkpoint updates the Flow row and creates a checkpoint (if needed) |
| 30 | +# and returns the updated row in the Flow table |
| 31 | +db_flow = await save_flow_checkpoint( |
24 | 32 | session=session, |
25 | | - flow_id=flow.id, |
| 33 | + flow_id=flow_id, |
26 | 34 | user_id=user.id, |
27 | | - flow=flow_update |
| 35 | + update_data=update_data |
28 | 36 | ) |
29 | 37 |
|
30 | | -# 3. Update the DB object |
31 | | -flow.data = new_flow_data |
32 | | -session.add(flow) |
33 | | -await session.commit() |
| 38 | +# 3. Flush/Refresh if needed (e.g. to get updated timestamps or IDs) |
| 39 | +await session.flush() |
| 40 | +await session.refresh(db_flow) |
34 | 41 | ``` |
35 | 42 |
|
36 | 43 | #### ❌ DO NOT DO THIS |
37 | | -If you update the object first, SQLAlchemy may flush that change before the checkpoint query runs, making the DB look identical to your new data. |
| 44 | +Do not update the database object manually before calling checkpoint, and do not expect `save_flow_checkpoint` to only handle versioning without updating the flow. (save_flow_checkpoint does both). |
38 | 45 |
|
39 | 46 | ```python |
40 | 47 | # 1. Update the DB object first (BAD!) |
41 | 48 | flow.data = new_flow_data |
| 49 | +session.add(flow) |
42 | 50 |
|
43 | | -# 2. Checkpoint too late |
44 | | -# The session now sees flow.data as the "current" state. |
45 | | -# save_flow_checkpoint will compare new_flow_data vs new_flow_data -> No Change detected. |
46 | | -await save_flow_checkpoint( |
47 | | - session=session, |
48 | | - flow_id=flow.id, |
49 | | - user_id=user.id, |
50 | | - flow=FlowUpdate(data=new_flow_data) |
51 | | -) |
| 51 | +# 2. Checkpoint too late or with wrong arguments |
| 52 | +# The session might already see flow.data as the "current" state, missing the change. |
| 53 | +await save_flow_checkpoint(...) |
52 | 54 | ``` |
0 commit comments