How the Simulation Manager Orchestrates Simulation Lifecycle and State Transitions in Mirofish
The SimulationManager in backend/app/services/simulation_manager.py drives simulations through seven distinct states—from creation to completion—by persisting state to disk, coordinating multi-stage preparation pipelines, and providing run-time instructions to external execution scripts.
The mirofish repository implements a robust simulation orchestration system where the SimulationManager serves as the central authority for managing distributed social media simulations. Understanding how this component handles simulation lifecycle and state transitions is essential for extending the platform or debugging complex multi-agent scenarios. The implementation uses a hybrid persistence model combining in-memory caching with JSON file storage to ensure durability across process restarts.
Core Architecture and State Model
The orchestration system centers on two critical data structures defined in backend/app/services/simulation_manager.py. The SimulationStatus enum (lines 24‑33) defines the canonical state machine with values: created, preparing, ready, running, paused, stopped, completed, and failed.
The SimulationState dataclass (lines 42‑78) encapsulates all metadata required for lifecycle management:
- Identifiers:
simulation_id,project_id,graph_id - Platform configuration:
enable_twitter,enable_redditbooleans - Progress tracking: Entity counts, profile generation metrics, current round
- Temporal data:
created_at,updated_attimestamps - Error handling: Optional
errorfield for failure diagnostics
State durability is guaranteed by the _save_simulation_state and _load_simulation_state helper methods (lines 44‑55 and 56‑73), which serialize to uploads/simulations/<simulation_id>/state.json and maintain synchronization with an in-memory cache.
Phase-by-Phase Lifecycle Orchestration
The manager progresses simulations through discrete phases, each implementing specific transition logic and persistence guarantees.
1. Creation and Initialization
The create_simulation method (lines 15‑23) initiates the lifecycle by:
- Generating a unique
simulation_id - Instantiating a
SimulationStateobject with statuscreated - Persisting the initial state to disk via
_save_simulation_state - Recording the mapping in the in-memory cache
from backend.app.services.simulation_manager import SimulationManager
mgr = SimulationManager()
state = mgr.create_simulation(
project_id="proj_123",
graph_id="graph_456",
enable_twitter=True,
enable_reddit=False,
)
print(state.simulation_id, state.status) # Output: sim_… created
2. Preparation Pipeline
The transition from created to ready occurs through the prepare_simulation method (lines 29‑47), which executes a multi-stage pipeline:
- Entity ingestion: Reads and filters nodes from a Zep knowledge graph using
ZepEntityReader - Profile generation: Creates OASIS Agent Profiles via
OasisProfileGeneratorwith optional LLM enrichment - Configuration synthesis: Generates
simulation_config.jsonusing LLM-driven parameters - Artifact persistence: Writes
reddit_profiles.jsonortwitter_profiles.csvto the simulation directory
The method sets status to preparing at line 66 and updates to ready upon successful completion (line 41).
def progress(stage, pct, msg, **kw):
print(f"[{stage}] {pct}% – {msg}")
state = mgr.prepare_simulation(
simulation_id=state.simulation_id,
simulation_requirement="Explore community sentiment about AI.",
document_text="Full text of the policy document …",
defined_entity_types=["person", "organization"],
use_llm_for_profiles=True,
progress_callback=progress,
parallel_profile_count=5,
)
print(state.status) # Output: ready
3. Execution Handoff
While the manager does not directly execute platform bots, it facilitates the transition to running by supplying execution parameters. The get_run_instructions method (lines 506‑528) assembles command strings for external runner scripts:
instr = mgr.get_run_instructions(state.simulation_id)
print(instr["commands"]["reddit"])
# Output: python /path/to/scripts/run_reddit_simulation.py --config /…/simulation_config.json
The actual status transition to running is performed by the external runner scripts (backend/scripts/run_reddit_simulation.py or run_twitter_simulation.py), which report their state back to the manager through the persistence layer.
4. Monitoring and Finalization
During execution, the manager exposes the get_simulation method (lines 58‑60) to retrieve the current SimulationState, enabling real-time status polling:
current = mgr.get_simulation(state.simulation_id)
print(current.to_simple_dict())
Terminal states are reached through distinct pathways:
completed: Set when runner scripts report successful terminationstopped: Triggered by manual intervention via API endpoints (defined inbackend/app/api/simulation.py)failed: Captured in theprepare_simulationexception handler (lines 49‑56), which updatesSimulationState.errorwith diagnostic information
State Transition Diagram
The complete lifecycle follows this deterministic sequence:
created→ Initial state aftercreate_simulationpreparing→ Entered at pipeline startready→ Preparation artifacts finalizedrunning→ External runners activatedpaused/stopped→ Manual control interventionscompleted→ Successful terminationfailed→ Exception or runtime error encountered
Each transition triggers an atomic write to state.json, ensuring that the system can recover to the last known valid state following unexpected crashes or restarts.
Summary
- The
SimulationManagerinbackend/app/services/simulation_manager.pyimplements a finite state machine with eight distinct statuses defined in theSimulationStatusenum. - State persistence uses JSON serialization to
uploads/simulations/<id>/state.jsonwith helper methods_save_simulation_stateand_load_simulation_stateensuring cache consistency. - The preparation pipeline (lines 29‑47) transitions simulations from
createdthroughpreparingtoreadyby orchestrating entity reading, profile generation, and configuration synthesis. - Execution decoupling allows the manager to remain platform-agnostic; external runner scripts consume prepared artifacts via
get_run_instructions(lines 506‑528) and manage therunningstate independently. - Error handling at lines 49‑56 ensures that pipeline failures transition the state to
failedand populate theerrorfield with exception details.
Frequently Asked Questions
How does the SimulationManager handle crashes during the preparation phase?
If an exception occurs within prepare_simulation, the catch block at lines 49‑56 immediately updates the simulation status to failed and persists the error message to SimulationState.error. Because the manager writes state atomically to disk at each phase transition, the system maintains a consistent record of the failure point without corrupting previous successful stages.
Can the simulation status be modified manually while external runners are executing?
Yes. While the external runner scripts (run_reddit_simulation.py and run_twitter_simulation.py) typically manage the running status, the HTTP API defined in backend/app/api/simulation.py exposes endpoints that allow authorized clients to transition states to paused or stopped. The manager treats these as terminal or interrupt states, though the external scripts must implement their own polling logic to respect these transitions.
What distinguishes the ready state from the created state in the simulation lifecycle?
The created state represents a minimal simulation record containing only identifiers and platform flags, whereas the ready state indicates that prepare_simulation has successfully executed the full pipeline: Zep graph entities have been ingested, OASIS profiles have been generated (potentially via LLM), and simulation_config.json has been written to disk. Only ready simulations possess the necessary artifacts for get_run_instructions to construct valid execution commands.
How does the manager support multiple simulations within the same project?
The list_simulations method filters the in-memory cache and persistent storage by project_id, returning all SimulationState objects associated with a given project. Each simulation maintains its own isolated directory under uploads/simulations/<simulation_id>/, preventing artifact collisions and allowing independent lifecycle management across concurrent simulations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →