Skip to content

fix(simulation): make create_simulation idempotent to prevent duplicate sims#690

Open
alreadyhavefeel wants to merge 1 commit into
666ghj:mainfrom
alreadyhavefeel:fix/idempotent-create-simulation
Open

fix(simulation): make create_simulation idempotent to prevent duplicate sims#690
alreadyhavefeel wants to merge 1 commit into
666ghj:mainfrom
alreadyhavefeel:fix/idempotent-create-simulation

Conversation

@alreadyhavefeel

Copy link
Copy Markdown

Problem

Creating a simulation is not idempotent. Each POST /api/simulation/create mints a fresh sim_<uuid> via SimulationManager.create_simulation. The frontend calls it through requestWithRetry(() => service.post('/api/simulation/create', data), 3, 1000) (frontend/src/api/simulation.js), so when the first request is slow or times out, the automatic retry fires a second create for the same project + graph.

Result: two identical simulations for the same project/graph, created ~2 seconds apart (matching the 1000 ms retry interval), which is confusing in the Simulation History UI.

Fix

Add an idempotency guard at the top of create_simulation: before minting a new id, reuse an existing simulation for the same project_id + graph_id (and matching enable_twitter / enable_reddit) when it has not been run yetcurrent_round == 0 and status in CREATED / PREPARING / READY.

A force_new=True parameter is added as an escape hatch for callers that deliberately want a brand-new simulation.

This makes the POST safe to retry (the real root cause is a non-idempotent POST behind an auto-retry).

Verification

Repeated POST /api/simulation/create for the same project now returns the same simulation_id instead of spawning duplicates.

Scope

Single-file change: backend/app/services/simulation_manager.py. No API signature change (the new param is optional and defaults to current behavior for fresh projects).

…te sims

Creating a simulation was not idempotent: each POST /api/simulation/create
minted a fresh sim_<uuid>. The frontend wraps createSimulation in
requestWithRetry(..., 3, 1000), so a slow/timed-out first request triggers a
retry that creates a second identical simulation for the same project+graph
(observed: two sims created ~2s apart).

Guard against this by reusing an existing, not-yet-run simulation for the same
project_id + graph_id (and matching platform flags) when status is
CREATED/PREPARING/READY and current_round == 0. A force_new=True escape hatch
preserves the ability to intentionally create a fresh simulation.

Verified: repeated /create calls now return the same simulation_id instead of
spawning duplicates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants