GSM-fastapi/serial_worker.py:72 creates self._send_queue = queue.Queue() with no maxsize. Under sustained load the queue grows without limit — no backpressure, no load shedding.
Compounding: api.py:306 send_sms is a sync FastAPI endpoint blocking up to 60s (api.py:324); _send_and_log blocks up to 120s (api.py:152). FastAPI runs sync endpoints in the anyio threadpool (default 40 workers), so ~40 concurrent SMS requests exhaust the pool and the whole GSM service stops responding — including /health (api.py:208), which is also sync.
Fix: give _send_queue a maxsize, and return HTTP 503 when full instead of blocking or growing unbounded.
Related: #227 (rate limiting).
GSM-fastapi/serial_worker.py:72 creates
self._send_queue = queue.Queue()with no maxsize. Under sustained load the queue grows without limit — no backpressure, no load shedding.Compounding:
api.py:306send_smsis a sync FastAPI endpoint blocking up to 60s (api.py:324);_send_and_logblocks up to 120s (api.py:152). FastAPI runs sync endpoints in the anyio threadpool (default 40 workers), so ~40 concurrent SMS requests exhaust the pool and the whole GSM service stops responding — including/health(api.py:208), which is also sync.Fix: give
_send_queueamaxsize, and return HTTP 503 when full instead of blocking or growing unbounded.Related: #227 (rate limiting).