This commit is contained in:
2026-09-18 15:21:47 +08:00
parent 0d8c34a2c9
commit aa27d35a47
55 changed files with 2842 additions and 471 deletions
+23
View File
@@ -78,6 +78,23 @@ class SimulationStore:
await db.execute(f"UPDATE simulations SET {', '.join(sets)} WHERE id = ?", vals)
await db.commit()
async def sweep_orphan_running_sims(self) -> int:
"""Mark any 'running' simulations as 'interrupted' on startup.
Running simulations live only in the current process — there is no
supervisor that resumes them after a restart. If we don't sweep them,
their status would stay 'running' forever and the report endpoint
would never return a terminal state.
Returns the number of sims swept.
"""
async with aiosqlite.connect(self.global_db_path) as db:
cursor = await db.execute(
"UPDATE simulations SET status = 'interrupted' WHERE status = 'running'"
)
await db.commit()
return cursor.rowcount or 0
async def get_simulation(self, sim_id: str) -> dict | None:
async with aiosqlite.connect(self.global_db_path) as db:
db.row_factory = aiosqlite.Row
@@ -238,6 +255,12 @@ class SimulationStore:
await db.execute("UPDATE simulations SET is_public = 1 WHERE id = ?", (sim_id,))
await db.commit()
async def unpublish(self, sim_id: str) -> None:
"""Remove a simulation from the gallery without deleting its data."""
async with aiosqlite.connect(self.global_db_path) as db:
await db.execute("UPDATE simulations SET is_public = 0 WHERE id = ?", (sim_id,))
await db.commit()
async def copy_state_at_round(self, source_sim_id: str, target_sim_id: str, round_num: int) -> None:
await self._init_sim_db(target_sim_id)
src_db_path = self._sim_db_path(source_sim_id)