Bump to v1.5.0: deduplicate detectors, fix aggregator bugs, fix blocking I/O
- Extract shared send_event/clear_event into detectors/base.py, removing ~150 lines of duplication across all 6 detectors - Fix default aggregator URL from port 5000 to 5100 in all detectors - Standardize cpu.py and memory.py to use active_alerts set pattern - Fix immediate emote rotation on startup (last_emote_change = time.time()) - Extract magic numbers to named constants in aggregator - Protect write_status() with try/except OSError - Fix notify event ID collision with monotonic counter - Replace blocking stream_output() with background daemon threads in kao.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
21
kao.py
21
kao.py
@@ -11,6 +11,7 @@ import os
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
@@ -59,11 +60,19 @@ class KaoManager:
|
||||
universal_newlines=True,
|
||||
)
|
||||
print(f"[{name}] Started (PID {process.pid})")
|
||||
# Read output in a background thread to avoid blocking the main loop
|
||||
thread = threading.Thread(target=self._read_output, args=(name, process), daemon=True)
|
||||
thread.start()
|
||||
return process
|
||||
except Exception as e:
|
||||
print(f"[{name}] Failed to start: {e}")
|
||||
return None
|
||||
|
||||
def _read_output(self, name, process):
|
||||
"""Read and print output from a process in a background thread."""
|
||||
for line in process.stdout:
|
||||
print(f"[{name}] {line.rstrip()}")
|
||||
|
||||
def wait_for_aggregator(self, url, timeout=AGGREGATOR_STARTUP_TIMEOUT):
|
||||
"""Wait for the aggregator to become available."""
|
||||
print(f"[aggregator] Waiting for service at {url}...")
|
||||
@@ -80,15 +89,6 @@ class KaoManager:
|
||||
print(f"[aggregator] Timeout waiting for service")
|
||||
return False
|
||||
|
||||
def stream_output(self, name, process):
|
||||
"""Read and print output from a process (non-blocking)."""
|
||||
if process.stdout:
|
||||
while True:
|
||||
line = process.stdout.readline()
|
||||
if not line:
|
||||
break
|
||||
print(f"[{name}] {line.rstrip()}")
|
||||
|
||||
def get_aggregator_url(self):
|
||||
"""Get aggregator URL from config port."""
|
||||
port = self.config.get("port", 5100)
|
||||
@@ -135,9 +135,6 @@ class KaoManager:
|
||||
for name, info in list(self.processes.items()):
|
||||
process = info["process"]
|
||||
|
||||
# Stream any available output
|
||||
self.stream_output(name, process)
|
||||
|
||||
# Check if process has exited
|
||||
if process.poll() is not None:
|
||||
print(f"[{name}] Exited with code {process.returncode}, restarting in {RESTART_DELAY}s...")
|
||||
|
||||
Reference in New Issue
Block a user