From 15efe56762c5fcdc5b37380e27c9414aefb97d75 Mon Sep 17 00:00:00 2001 From: Smittix Date: Sun, 8 Feb 2026 16:00:31 +0000 Subject: [PATCH] Detect grgsm_scanner crash-on-startup and report to UI grgsm_scanner exits in <300ms with osmo_fsm assertion error due to libosmocore incompatibility. Added crash detection: if process exits in <5s with non-zero code, counts as crash. After 3 crashes, stops retrying and sends error to SSE stream so the UI can display it. Also drains remaining queue items after process exits and logs exit code and scan duration for diagnostics. Co-Authored-By: Claude Opus 4.6 --- routes/gsm_spy.py | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/routes/gsm_spy.py b/routes/gsm_spy.py index 4d70227..5949158 100644 --- a/routes/gsm_spy.py +++ b/routes/gsm_spy.py @@ -1218,6 +1218,7 @@ def scanner_thread(cmd, device_index): strongest_tower = None auto_monitor_triggered = False # Moved outside loop - persists across scans scan_count = 0 + crash_count = 0 process = None try: @@ -1266,7 +1267,8 @@ def scanner_thread(cmd, device_index): stderr_thread.start() # Process output with timeout - last_output = time.time() + scan_start = time.time() + last_output = scan_start scan_timeout = 120 # 2 minute maximum per scan while app_module.gsm_spy_scanner_running: @@ -1326,6 +1328,15 @@ def scanner_thread(cmd, device_index): logger.warning(f"Scan timeout after {scan_timeout}s") break + # Drain remaining queue items after process exits + while not output_queue_local.empty(): + try: + msg_type, line = output_queue_local.get_nowait() + if line: + logger.info(f"Scanner [{msg_type}] (drain): {line.strip()}") + except queue.Empty: + break + # Clean up process with timeout if process.poll() is None: logger.info("Terminating scanner process") @@ -1333,7 +1344,30 @@ def scanner_thread(cmd, device_index): else: process.wait() # Reap zombie - logger.info(f"Scan #{scan_count} complete") + exit_code = process.returncode + scan_duration = time.time() - scan_start + logger.info(f"Scan #{scan_count} complete (exit code: {exit_code}, duration: {scan_duration:.1f}s)") + + # Detect crash pattern: process exits too quickly with no data + if scan_duration < 5 and exit_code != 0: + crash_count += 1 + logger.error( + f"grgsm_scanner crashed on startup (exit code: {exit_code}). " + f"Crash count: {crash_count}. Check gr-gsm/libosmocore compatibility." + ) + try: + app_module.gsm_spy_queue.put_nowait({ + 'type': 'error', + 'message': f'grgsm_scanner crashed (exit code: {exit_code}). ' + 'This may be a gr-gsm/libosmocore compatibility issue. ' + 'Try rebuilding gr-gsm from source.', + 'timestamp': time.strftime('%Y-%m-%dT%H:%M:%S') + }) + except queue.Full: + pass + if crash_count >= 3: + logger.error("grgsm_scanner crashed 3 times, stopping scanner") + break except FileNotFoundError: logger.error(