Stage 1: Entry and Run Lifecycle
Course: DeerFlow Source Code Class · Stage Assignment Prerequisite: Stage 0 Corresponding Overview:
run-lifecycle.mdGoal of This Stage: Accurately state the moments when a Run is accepted, started, loses ownership, and completed.
1. What This Stage Addresses
Section titled “1. What This Stage Addresses”An execution is not “calling a function and waiting for a return,” but rather a work order with an identity:
POST request → start_run Authorization and Cleansing → create_or_reject Atom registered as pending → Return RunResponse / Create SSE → worker try_start condition changed to running → astream execute → journal / checkpoint / delivery receipt → success / error / interruptedthread_runs.py’s create_run, stream_run, and wait_run are just three consumption patterns, all ultimately going through services.start_run.
2. First, remember a judgment
Section titled “2. First, remember a judgment”Accepting an order and starting work are two different commitments.
create_or_reject() answers “whether this work order is allowed to exist”; try_start() answers “whether there actually is a worker who can take it now.” Combining the two will cause queuing, cancellations, idempotency, and concurrent starts to lose their atomic boundaries.
3. Mainline of the source code
Section titled “3. Mainline of the source code”thread_runs.py::create_runcallsstart_run.start_runchecks cancellation ability, model whitelist, thread ownership, and input/internal key sanitization.start_runassembles the server-trustedRunContext, then callsRunManager.create_or_reject.create_or_rejectprocesses idempotent keys, same-thread policies, andpendingrecords within a controlled block.- Background workers enter
run_agent, first invokingrun_manager.try_start(run_id). try_startonly changes it torunningif the confirmation record is stillpendingand owner/lease is valid.- During graph execution, facts are recorded separately by
RunJournal,StreamBridge, and checkpoints. - Finally, it ends with
set_finalizing, delivery receipt, status writing, and resource release.
4. Key objects and contracts
Section titled “4. Key objects and contracts”| Contract | Meaning | Failure consequence |
|---|---|---|
| Idempotent key | Replaying the same request cannot produce two work orders | Duplicate side effects, duplicate billing |
| Thread ownership | Only an authorized owner can create a Run | Cross-user read/write |
pending |
Registered but not started | Misreporting ‘accepted’ as ‘in progress’ |
try_start |
The sole gate for starting work | Multiple workers executing simultaneously |
ownership_lost |
This worker has lost write permission | Zombie writes overwrite new owner |
| finalizing | Exclusive finalizing block before terminal state | Delivery and success state not closed |
5. An observable chain
Section titled “5. An observable chain”create_run → start_run → create_or_reject: pending → background worker → try_start: running → run_agent / astream → finalizing → delivery receipt → terminalKey observations: cancellations may occur at pending, waiting for the previous Run finalizing, model flow, and tool boundaries; Finishing varies at different locations, but none can be successfully forged.
6. Experiment
Section titled “6. Experiment”Experiment A: Verifying “Returning does not equal starting work”
Section titled “Experiment A: Verifying “Returning does not equal starting work””After creating a run, query the status immediately; Then observe in the cancelled branch of try_start. Reference acceptance: pending → interrupted should be visible, and no model construction or initialization tools should be used.
Experiment B: Verify the Idempotency
Section titled “Experiment B: Verify the Idempotency”Commit twice concurrently using the same idempotent key. Reference observation: Only one valid ticket is generated, and the other takes a reuse or conflict path, rather than two workers running simultaneously.
Experiment C: Verifying the delivery threshold
Section titled “Experiment C: Verifying the delivery threshold”Have the Agent only say “report.md generated” but do not write the file. Reference acceptance: Success cannot be marked solely by natural language; The delivered content must correspond to the real product.
Experimental Reference Answers
Section titled “Experimental Reference Answers”- Immediate queries should see that
pendinghas not yet been executed; If canceled beforetry_start, it entersinterruptedwithout constructing models, initializing tools, or causing runtime side effects. - Only one executable work order can be left for two commits; The second time should hit idempotent multiplexing or conflict, and two workers must not have the same run simultaneously.
- Only natural language “generated” cannot achieve clean success. Delivery must correspond to real products, receipts, or verifiable outputs; If products are missing, failures or marks should be incomplete.
7. Failure and recovery
Section titled “7. Failure and recovery”| Collapse location | Existing facts | Restoration principles |
|---|---|---|
create_or_reject Previous |
No work order | Client can safely retry |
| After Pending, Before Work Start | With Work Orders, No Execution | Cancel or Reschedule |
| running | There are leases, events, and some checkpoints | Restored by the receiver, the old worker stops writing |
| finalizing | Result generated, terminal state not closed | First read journal/receipt, only add closing |
| After writing the final state | Work order completed | Only perform idempotent playback, do not rerun the tool |
8. Pass through customs and self-test
Section titled “8. Pass through customs and self-test”- Why must both
create_or_reject()andtry_start()exist? - Under what conditions does Run change from
pendingtorunning? ownership_lostWhy must we stop writing the final state?- When canceling during tool execution, which actions cannot be pretended to roll back?
Reference answers
Section titled “Reference answers”- The former solves order queues: idempotent, same-thread policy, and whether to allow work order creation; The latter resolves start queues: cancel, concurrent worker, and lease. Merging causes “allow existence” and “actually someone to execute” to form an unstable commitment.
- Only when a worker qualifies to start work, with the record still
pending, and the owner/lease condition is met, only then istry_start()carried out. HTTP returns, SSE connection, and task enqueuement cannot prove that the process is running. - After losing ownership, the old worker’s final state, receipt, title, or usage will override the legitimate result of the new owner; It should stop persistence and hand over recovery responsibility to the receiver.
- Side effects such as external file writes, network requests, or message sending that have occurred cannot be “canceled” and erased; Partial execution, use idempotents, or readback to check if it is effective; blind redoing is not allowed.
9. Source code coordinates
Section titled “9. Source code coordinates”backend/app/gateway/routers/thread_runs.pybackend/app/gateway/services.py::start_runbackend/packages/harness/deerflow/runtime/runs/manager.pybackend/packages/harness/deerflow/runtime/runs/worker.py::run_agentbackend/packages/harness/deerflow/runtime/journal.py
10. Next
Section titled “10. Next”Entering Stage 2: Run has already running, so what models, tools, and middleware will LangGraph assemble next?