atakan Claude Sonnet 5 commited on
Commit
80cc518
·
1 Parent(s): f971ecf

fix: Serialize inference requests to prevent concurrent llama.cpp crashes

Browse files

llama_cpp's Llama object isn't safe for concurrent generation calls --
two simultaneous requests hitting the same model instance corrupted
its state and crashed the worker (observed live: two overlapping chat
requests both failed with a stream INTERNAL_ERROR and the container
restarted). A single lock now serializes every request through the
shared model instance; concurrent users queue instead of crashing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +9 -3
app.py CHANGED
@@ -6,6 +6,7 @@ import json
6
  import os
7
  import shutil
8
  import sys
 
9
  import time
10
  from contextlib import asynccontextmanager
11
  from pathlib import Path
@@ -65,6 +66,9 @@ if STATIC_DIR.exists():
65
 
66
  # Initialize Agent
67
  agent_instance: ControlAIAgent | None = None
 
 
 
68
 
69
 
70
  def get_agent() -> ControlAIAgent:
@@ -181,8 +185,9 @@ async def chat_stream_endpoint(req: ChatRequest):
181
 
182
  def event_generator():
183
  try:
184
- for event in agent.run_stream(req.message.strip(), history=req.history):
185
- yield f"data: {json.dumps(event, ensure_ascii=False)}\n\n"
 
186
  except Exception as exc:
187
  yield f"data: {json.dumps({'type': 'error', 'error': str(exc)}, ensure_ascii=False)}\n\n"
188
 
@@ -205,7 +210,8 @@ async def chat_endpoint(req: ChatRequest) -> ChatResponse:
205
  t0 = time.time()
206
  try:
207
  agent = get_agent()
208
- result = agent.run(req.message.strip(), history=req.history, verbose=False)
 
209
  elapsed = time.time() - t0
210
 
211
  # Collect tool traces
 
6
  import os
7
  import shutil
8
  import sys
9
+ import threading
10
  import time
11
  from contextlib import asynccontextmanager
12
  from pathlib import Path
 
66
 
67
  # Initialize Agent
68
  agent_instance: ControlAIAgent | None = None
69
+ # llama.cpp's Llama object is not safe for concurrent generation calls from
70
+ # multiple threads; serialize every request through the single model instance.
71
+ inference_lock = threading.Lock()
72
 
73
 
74
  def get_agent() -> ControlAIAgent:
 
185
 
186
  def event_generator():
187
  try:
188
+ with inference_lock:
189
+ for event in agent.run_stream(req.message.strip(), history=req.history):
190
+ yield f"data: {json.dumps(event, ensure_ascii=False)}\n\n"
191
  except Exception as exc:
192
  yield f"data: {json.dumps({'type': 'error', 'error': str(exc)}, ensure_ascii=False)}\n\n"
193
 
 
210
  t0 = time.time()
211
  try:
212
  agent = get_agent()
213
+ with inference_lock:
214
+ result = agent.run(req.message.strip(), history=req.history, verbose=False)
215
  elapsed = time.time() - t0
216
 
217
  # Collect tool traces