- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
95 lines
3.6 KiB
Python
95 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import sys
|
|
sys.path.insert(0, '.')
|
|
|
|
# Test d'exécution ligne par ligne
|
|
try:
|
|
print("1. Importing modules...")
|
|
import logging
|
|
from collections import defaultdict
|
|
from datetime import datetime, timedelta
|
|
from typing import Dict, List, Any
|
|
from core.system.models import SimpleFailureEvent
|
|
print("✓ All imports successful")
|
|
|
|
print("2. Creating logger...")
|
|
logger = logging.getLogger(__name__)
|
|
print("✓ Logger created")
|
|
|
|
print("3. Defining SimpleFailureWindow...")
|
|
class SimpleFailureWindow:
|
|
def __init__(self, window_start: datetime, window_duration_s: int, failures: List = None):
|
|
self.window_start = window_start
|
|
self.window_duration_s = window_duration_s
|
|
self.failures = failures or []
|
|
|
|
def add_failure(self, failure: SimpleFailureEvent) -> None:
|
|
self.failures.append(failure)
|
|
self.cleanup_expired()
|
|
|
|
def get_failure_count(self) -> int:
|
|
self.cleanup_expired()
|
|
return len(self.failures)
|
|
|
|
def cleanup_expired(self) -> None:
|
|
now = datetime.now()
|
|
cutoff = now - timedelta(seconds=self.window_duration_s)
|
|
self.failures = [f for f in self.failures if f.timestamp >= cutoff]
|
|
|
|
print("✓ SimpleFailureWindow defined")
|
|
|
|
print("4. Defining CircuitBreaker...")
|
|
class CircuitBreaker:
|
|
def __init__(self, policy: Dict[str, Any]):
|
|
self.policy = policy
|
|
self.step_consecutive_failures: Dict[str, List] = defaultdict(list)
|
|
self.workflow_windows: Dict[str, SimpleFailureWindow] = {}
|
|
self.global_window = SimpleFailureWindow(
|
|
window_start=datetime.now(),
|
|
window_duration_s=policy.get('workflow_fail_window_s', 600),
|
|
failures=[]
|
|
)
|
|
self.step_success_counts: Dict[str, int] = defaultdict(int)
|
|
logger.info("CircuitBreaker initialized")
|
|
|
|
def record_failure(self, workflow_id: str, step_id: str, failure_type: str) -> None:
|
|
now = datetime.now()
|
|
step_key = f"{workflow_id}:{step_id}"
|
|
|
|
failure_event = SimpleFailureEvent(
|
|
timestamp=now,
|
|
workflow_id=workflow_id,
|
|
step_id=step_id,
|
|
failure_type=failure_type
|
|
)
|
|
|
|
self.step_consecutive_failures[step_key].append(failure_event)
|
|
self.step_success_counts[step_key] = 0
|
|
|
|
if workflow_id not in self.workflow_windows:
|
|
self.workflow_windows[workflow_id] = SimpleFailureWindow(
|
|
window_start=now,
|
|
window_duration_s=self.policy.get('workflow_fail_window_s', 600),
|
|
failures=[]
|
|
)
|
|
self.workflow_windows[workflow_id].add_failure(failure_event)
|
|
self.global_window.add_failure(failure_event)
|
|
|
|
print("✓ CircuitBreaker defined")
|
|
|
|
print("5. Testing CircuitBreaker...")
|
|
cb = CircuitBreaker({'test': True})
|
|
print("✓ CircuitBreaker instance created")
|
|
print("Available methods:", [method for method in dir(cb) if not method.startswith('_')])
|
|
print("Has record_failure:", hasattr(cb, 'record_failure'))
|
|
|
|
if hasattr(cb, 'record_failure'):
|
|
print("6. Testing record_failure...")
|
|
cb.record_failure("test_workflow", "test_step", "TEST_ERROR")
|
|
print("✓ record_failure works")
|
|
|
|
except Exception as e:
|
|
print(f"✗ Error: {e}")
|
|
import traceback
|
|
traceback.print_exc() |