SemSorter commited on
Commit
c27555f
·
1 Parent(s): fee931d

Initialize simulation as background task to fix WS timeout on Render

Browse files
Files changed (1) hide show
  1. SemSorter/server/app.py +7 -14
SemSorter/server/app.py CHANGED
@@ -140,11 +140,16 @@ async def _simulation_tick_loop() -> None:
140
 
141
  @app.on_event("startup")
142
  async def startup():
143
- global _main_loop, _frame_ready_event
144
  _main_loop = asyncio.get_running_loop()
145
  _frame_ready_event = asyncio.Event()
146
  bridge.set_frame_ready_event(_main_loop, _frame_ready_event)
147
- logger.info("Server ready (Simulation will load lazily on first connect)")
 
 
 
 
 
148
 
149
 
150
  @app.on_event("shutdown")
@@ -231,12 +236,6 @@ async def ws_chat(ws: WebSocket):
231
  _chat_clients.add(ws)
232
  logger.info("Chat client connected (%d total)", len(_chat_clients))
233
 
234
- # Lazily start simulation if this is the first client
235
- if _sim_tick_task is None:
236
- logger.info("First client connected; starting MuJoCo simulation...")
237
- await bridge.run_in_sim_thread(bridge.get_simulation)
238
- _sim_tick_task = asyncio.create_task(_simulation_tick_loop())
239
-
240
  try:
241
  await ws.send_text(json.dumps({
242
  "type": "welcome",
@@ -323,12 +322,6 @@ async def ws_video(ws: WebSocket):
323
  _video_clients.add(ws)
324
  logger.info("Video client connected")
325
 
326
- # Lazily start simulation if this is the first client
327
- if _sim_tick_task is None:
328
- logger.info("First client connected; starting MuJoCo simulation...")
329
- await bridge.run_in_sim_thread(bridge.get_simulation)
330
- _sim_tick_task = asyncio.create_task(_simulation_tick_loop())
331
-
332
  try:
333
  while True:
334
  # Wait for new frame (event-driven; sends exactly when sim produces one)
 
140
 
141
  @app.on_event("startup")
142
  async def startup():
143
+ global _main_loop, _frame_ready_event, _sim_tick_task
144
  _main_loop = asyncio.get_running_loop()
145
  _frame_ready_event = asyncio.Event()
146
  bridge.set_frame_ready_event(_main_loop, _frame_ready_event)
147
+ logger.info("Server ready. Backgrounding simulation initialization...")
148
+
149
+ # Initialize the simulation asynchronously in the background so it doesn't block
150
+ # the main event loop and cause WS timeouts on low-CPU instances like Render Free Tier.
151
+ asyncio.create_task(bridge.run_in_sim_thread(bridge.get_simulation))
152
+ _sim_tick_task = asyncio.create_task(_simulation_tick_loop())
153
 
154
 
155
  @app.on_event("shutdown")
 
236
  _chat_clients.add(ws)
237
  logger.info("Chat client connected (%d total)", len(_chat_clients))
238
 
 
 
 
 
 
 
239
  try:
240
  await ws.send_text(json.dumps({
241
  "type": "welcome",
 
322
  _video_clients.add(ws)
323
  logger.info("Video client connected")
324
 
 
 
 
 
 
 
325
  try:
326
  while True:
327
  # Wait for new frame (event-driven; sends exactly when sim produces one)