init commit

This commit is contained in:
zyhe
2026-03-16 11:44:10 +00:00
commit 94384a93c9
552 changed files with 363038 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
# flake8: noqa: E401
from .status import ComponentStatus, StatusInfo
from .status_monitor import StatusMonitor
from .status_reporter import StatusReporter

View File

@@ -0,0 +1,24 @@
from functools import wraps
from nimbus.daemon import ComponentStatus, StatusReporter
def status_monitor(running_status=ComponentStatus.RUNNING, completed_status=ComponentStatus.COMPLETED):
def decorator(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
if not hasattr(self, "status_reporter"):
self.status_reporter = StatusReporter(self.__class__.__name__)
self.status_reporter.update_status(running_status)
try:
result = func(self, *args, **kwargs)
self.status_reporter.update_status(completed_status)
return result
except Exception as e:
raise e
return wrapper
return decorator

21
nimbus/daemon/status.py Normal file
View File

@@ -0,0 +1,21 @@
import time
from dataclasses import dataclass, field
from enum import Enum
class ComponentStatus(Enum):
IDLE = "idle"
READY = "ready"
RUNNING = "running"
COMPLETED = "completed"
TIMEOUT = "timeout"
@dataclass
class StatusInfo:
component_id: str
status: ComponentStatus
last_update: float = field(default_factory=time.time)
def get_status_duration(self) -> float:
return time.time() - self.last_update

View File

@@ -0,0 +1,160 @@
import threading
from typing import Dict, Optional
from .status import ComponentStatus, StatusInfo
class StatusMonitor:
_instance = None
_lock = threading.Lock()
DEFAULT_TIMEOUTS = {
ComponentStatus.IDLE: 100,
ComponentStatus.READY: float("inf"),
ComponentStatus.RUNNING: 360,
ComponentStatus.COMPLETED: float("inf"),
ComponentStatus.TIMEOUT: float("inf"),
}
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not hasattr(self, "initialized"):
self.components: Dict[str, StatusInfo] = {}
self.status_timeouts = self.DEFAULT_TIMEOUTS.copy()
self.initialized = True
@classmethod
def get_instance(cls):
return cls()
def set_logger(self, logger):
self.logger = logger
def set_status_timeout(self, status: ComponentStatus, timeout_seconds: float):
self.status_timeouts[status] = timeout_seconds
def set_component_timeouts(self, timeouts: Dict[str, float]):
converted_timeouts = {}
for status_name, timeout_value in timeouts.items():
try:
if isinstance(status_name, str):
status = ComponentStatus[status_name.upper()]
elif isinstance(status_name, ComponentStatus):
status = status_name
else:
self._record(
f"Warning: Invalid status type '{type(status_name)}' for status '{status_name}', skipping"
)
continue
try:
timeout_value = float(timeout_value)
if timeout_value < 0:
timeout_value = float("inf")
converted_timeouts[status] = timeout_value
self._record(f"Set timeout for {status.value}: {timeout_value}s")
except (ValueError, TypeError) as e:
self._record(
f"Warning: Invalid timeout value '{timeout_value}' for status '{status_name}': {e}, skipping"
)
continue
except KeyError:
self._record(
f"Warning: Unknown status '{status_name}', skipping. Available statuses:"
f" {[s.name for s in ComponentStatus]}"
)
continue
except Exception as e:
self._record(f"Error processing status '{status_name}': {e}, skipping")
continue
self.status_timeouts.update(converted_timeouts)
def register_update(self, status_info: StatusInfo):
self.components[status_info.component_id] = status_info
def get_all_status(self) -> Dict[str, StatusInfo]:
return self.components.copy()
def get_status(self, component_id: str) -> Optional[StatusInfo]:
return self.components.get(component_id)
def get_timeout_components(self) -> Dict[str, StatusInfo]:
timeout_components = {}
for component_id, status_info in self.components.items():
if status_info.status == ComponentStatus.TIMEOUT:
timeout_components[component_id] = status_info
return timeout_components
def get_components_length(self):
return len(self.components)
def check_and_update_timeouts(self) -> Dict[str, StatusInfo]:
newly_timeout_components = {}
components = self.get_all_status()
for component_id, status_info in components.items():
if status_info.status == ComponentStatus.TIMEOUT:
newly_timeout_components[component_id] = status_info
continue
time_since_update = status_info.get_status_duration()
timeout_threshold = self.status_timeouts.get(status_info.status, 300)
self._record(
f"[COMPONENT DETAIL] {component_id}: "
f"Status={status_info.status}, "
f"Duration={status_info.get_status_duration():.1f}s, "
f"Threshold={timeout_threshold}s"
)
if time_since_update > timeout_threshold:
self._record(
f"Component {component_id} timeout: {status_info.status.value} for {time_since_update:.1f}s"
f" (threshold: {timeout_threshold}s)"
)
status_info.status = ComponentStatus.TIMEOUT
status_info.last_update = time_since_update
newly_timeout_components[component_id] = status_info
return newly_timeout_components
def clear(self):
self.components.clear()
self._record("Cleared all registered components.")
def get_component_status_duration(self, component_id: str) -> Optional[float]:
status_info = self.components.get(component_id)
if status_info:
return status_info.get_status_duration()
return None
def get_all_status_with_duration(self) -> Dict[str, Dict]:
result = {}
for comp_id, status_info in self.components.items():
result[comp_id] = {
"status": status_info.status,
"duration": status_info.get_status_duration(),
"timeout_threshold": self.status_timeouts.get(status_info.status, 300),
"last_update": status_info.last_update,
}
return result
def set_check_interval(self, interval_seconds: float):
self.check_interval = interval_seconds
self._record(f"Set daemon check interval to {interval_seconds}s")
def _record(self, info):
if hasattr(self, "logger") and self.logger is not None:
self.logger.info(f"[STATUS MONITOR]: {info}")
else:
print(f"[STATUS MONITOR]: {info}")

View File

@@ -0,0 +1,21 @@
import threading
import time
from .status import ComponentStatus, StatusInfo
from .status_monitor import StatusMonitor
class StatusReporter:
def __init__(self, component_id: str):
self.component_id = component_id
self._status_info = StatusInfo(component_id, ComponentStatus.IDLE)
self._lock = threading.Lock()
def update_status(self, status: ComponentStatus):
with self._lock:
self._status_info = StatusInfo(component_id=self.component_id, status=status, last_update=time.time())
StatusMonitor.get_instance().register_update(self._status_info)
def get_status(self) -> StatusInfo:
with self._lock:
return self._status_info