diff --git a/core/tool_manager.py b/core/tool_manager.py index 2ad6f8c..a28bb5b 100644 --- a/core/tool_manager.py +++ b/core/tool_manager.py @@ -336,28 +336,33 @@ class ToolManager: "restart_count": tool.restart_count}, source_module="tool_manager") - # Crash callback (e.g., corrective ARP) - if tool.crash_callback: + # Call crash callback OUTSIDE lock to prevent deadlock + callback = tool.crash_callback + restart_needed = tool.restart_count < tool.max_restarts + + # Release lock before callback + if callback: try: - tool.crash_callback() + callback() except Exception: logger.exception("Crash callback failed for %s", tool.name) - - # Auto-restart with exponential backoff - if tool.restart_count < tool.max_restarts: - backoff = min(2 ** tool.restart_count, 30) - logger.info("Restarting %s in %ds (attempt %d/%d)", - tool.name, backoff, tool.restart_count + 1, - tool.max_restarts) - time.sleep(backoff) - tool.restart_count += 1 - with self._lock: + + # Re-acquire lock for restart decision + with self._lock: + # Auto-restart with exponential backoff + if tool.restart_count < tool.max_restarts: + backoff = min(2 ** tool.restart_count, 30) + logger.info("Restarting %s in %ds (attempt %d/%d)", + tool.name, backoff, tool.restart_count + 1, + tool.max_restarts) + time.sleep(backoff) + tool.restart_count += 1 self._start_tool(tool) - else: - logger.error("Tool %s exceeded max restarts (%d), giving up", - tool.name, tool.max_restarts) - tool.process = None - tool.pid = None + else: + logger.error("Tool %s exceeded max restarts (%d), giving up", + tool.name, tool.max_restarts) + tool.process = None + tool.pid = None elif tool.health_check: # Process alive — run health check