mirror of
https://github.com/smittix/intercept.git
synced 2026-07-16 05:18:10 -07:00
fix(meshcore): run BLE scan in dedicated thread to avoid gevent conflict
asyncio.run() called from a gevent-patched Flask thread fails under gunicorn+gevent. Run the one-shot scan in a ThreadPoolExecutor thread with its own event loop, matching how AsyncWorker handles it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+18
-6
@@ -416,16 +416,28 @@ class MeshcoreClient:
|
|||||||
"""Scan for BLE MeshCore devices; works with or without an active connection."""
|
"""Scan for BLE MeshCore devices; works with or without an active connection."""
|
||||||
if self._worker:
|
if self._worker:
|
||||||
return self._worker.scan_ble_sync()
|
return self._worker.scan_ble_sync()
|
||||||
# No worker yet — run a one-shot scan directly
|
# No worker — spin up a dedicated thread with its own event loop to avoid
|
||||||
|
# conflicts with gevent's monkey-patched event loop in the Flask thread.
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
from utils.meshcore_client import _scan_ble
|
from utils.meshcore_client import _scan_ble
|
||||||
|
|
||||||
try:
|
def _run() -> list[dict]:
|
||||||
return asyncio.run(_scan_ble())
|
loop = asyncio.new_event_loop()
|
||||||
except Exception as exc:
|
asyncio.set_event_loop(loop)
|
||||||
logger.warning("BLE scan failed: %s", exc)
|
try:
|
||||||
return []
|
return loop.run_until_complete(_scan_ble())
|
||||||
|
finally:
|
||||||
|
loop.close()
|
||||||
|
asyncio.set_event_loop(None)
|
||||||
|
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
||||||
|
try:
|
||||||
|
return executor.submit(_run).result(timeout=12)
|
||||||
|
except Exception as exc:
|
||||||
|
logger.warning("BLE scan failed: %s", exc)
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
_client: MeshcoreClient | None = None
|
_client: MeshcoreClient | None = None
|
||||||
|
|||||||
Reference in New Issue
Block a user