unrealon 1.0.9__py3-none-any.whl → 1.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unrealon/__init__.py +23 -21
- unrealon-1.1.1.dist-info/METADATA +722 -0
- unrealon-1.1.1.dist-info/RECORD +82 -0
- {unrealon-1.0.9.dist-info → unrealon-1.1.1.dist-info}/WHEEL +1 -1
- unrealon-1.1.1.dist-info/entry_points.txt +9 -0
- {unrealon-1.0.9.dist-info → unrealon-1.1.1.dist-info/licenses}/LICENSE +1 -1
- unrealon_bridge/__init__.py +114 -0
- unrealon_bridge/cli.py +316 -0
- unrealon_bridge/client/__init__.py +93 -0
- unrealon_bridge/client/base.py +78 -0
- unrealon_bridge/client/commands.py +89 -0
- unrealon_bridge/client/connection.py +90 -0
- unrealon_bridge/client/events.py +65 -0
- unrealon_bridge/client/health.py +38 -0
- unrealon_bridge/client/html_parser.py +146 -0
- unrealon_bridge/client/logging.py +139 -0
- unrealon_bridge/client/proxy.py +70 -0
- unrealon_bridge/client/scheduler.py +450 -0
- unrealon_bridge/client/session.py +70 -0
- unrealon_bridge/configs/__init__.py +14 -0
- unrealon_bridge/configs/bridge_config.py +212 -0
- unrealon_bridge/configs/bridge_config.yaml +39 -0
- unrealon_bridge/models/__init__.py +138 -0
- unrealon_bridge/models/base.py +28 -0
- unrealon_bridge/models/command.py +41 -0
- unrealon_bridge/models/events.py +40 -0
- unrealon_bridge/models/html_parser.py +79 -0
- unrealon_bridge/models/logging.py +55 -0
- unrealon_bridge/models/parser.py +63 -0
- unrealon_bridge/models/proxy.py +41 -0
- unrealon_bridge/models/requests.py +95 -0
- unrealon_bridge/models/responses.py +88 -0
- unrealon_bridge/models/scheduler.py +592 -0
- unrealon_bridge/models/session.py +28 -0
- unrealon_bridge/server/__init__.py +91 -0
- unrealon_bridge/server/base.py +171 -0
- unrealon_bridge/server/handlers/__init__.py +23 -0
- unrealon_bridge/server/handlers/command.py +110 -0
- unrealon_bridge/server/handlers/html_parser.py +139 -0
- unrealon_bridge/server/handlers/logging.py +95 -0
- unrealon_bridge/server/handlers/parser.py +95 -0
- unrealon_bridge/server/handlers/proxy.py +75 -0
- unrealon_bridge/server/handlers/scheduler.py +545 -0
- unrealon_bridge/server/handlers/session.py +66 -0
- unrealon_browser/__init__.py +61 -18
- unrealon_browser/{src/cli → cli}/browser_cli.py +6 -13
- unrealon_browser/{src/cli → cli}/cookies_cli.py +5 -1
- unrealon_browser/{src/core → core}/browser_manager.py +2 -2
- unrealon_browser/{src/managers → managers}/captcha.py +1 -1
- unrealon_browser/{src/managers → managers}/cookies.py +1 -1
- unrealon_browser/managers/logger_bridge.py +231 -0
- unrealon_browser/{src/managers → managers}/profile.py +1 -1
- unrealon_driver/__init__.py +73 -19
- unrealon_driver/browser/__init__.py +8 -0
- unrealon_driver/browser/config.py +74 -0
- unrealon_driver/browser/manager.py +416 -0
- unrealon_driver/exceptions.py +28 -0
- unrealon_driver/parser/__init__.py +55 -0
- unrealon_driver/parser/cli_manager.py +141 -0
- unrealon_driver/parser/daemon_manager.py +227 -0
- unrealon_driver/parser/managers/__init__.py +46 -0
- unrealon_driver/parser/managers/browser.py +51 -0
- unrealon_driver/parser/managers/config.py +281 -0
- unrealon_driver/parser/managers/error.py +412 -0
- unrealon_driver/parser/managers/html.py +732 -0
- unrealon_driver/parser/managers/logging.py +609 -0
- unrealon_driver/parser/managers/result.py +321 -0
- unrealon_driver/parser/parser_manager.py +628 -0
- unrealon/sdk_config.py +0 -88
- unrealon-1.0.9.dist-info/METADATA +0 -810
- unrealon-1.0.9.dist-info/RECORD +0 -246
- unrealon_browser/pyproject.toml +0 -182
- unrealon_browser/src/__init__.py +0 -62
- unrealon_browser/src/managers/logger_bridge.py +0 -395
- unrealon_driver/README.md +0 -204
- unrealon_driver/pyproject.toml +0 -187
- unrealon_driver/src/__init__.py +0 -90
- unrealon_driver/src/cli/__init__.py +0 -10
- unrealon_driver/src/cli/main.py +0 -66
- unrealon_driver/src/cli/simple.py +0 -510
- unrealon_driver/src/config/__init__.py +0 -11
- unrealon_driver/src/config/auto_config.py +0 -478
- unrealon_driver/src/core/__init__.py +0 -18
- unrealon_driver/src/core/exceptions.py +0 -289
- unrealon_driver/src/core/parser.py +0 -638
- unrealon_driver/src/dto/__init__.py +0 -66
- unrealon_driver/src/dto/cli.py +0 -119
- unrealon_driver/src/dto/config.py +0 -18
- unrealon_driver/src/dto/events.py +0 -237
- unrealon_driver/src/dto/execution.py +0 -313
- unrealon_driver/src/dto/services.py +0 -311
- unrealon_driver/src/execution/__init__.py +0 -23
- unrealon_driver/src/execution/daemon_mode.py +0 -317
- unrealon_driver/src/execution/interactive_mode.py +0 -88
- unrealon_driver/src/execution/modes.py +0 -45
- unrealon_driver/src/execution/scheduled_mode.py +0 -209
- unrealon_driver/src/execution/test_mode.py +0 -250
- unrealon_driver/src/logging/__init__.py +0 -24
- unrealon_driver/src/logging/driver_logger.py +0 -512
- unrealon_driver/src/services/__init__.py +0 -24
- unrealon_driver/src/services/browser_service.py +0 -726
- unrealon_driver/src/services/llm/__init__.py +0 -15
- unrealon_driver/src/services/llm/browser_llm_service.py +0 -363
- unrealon_driver/src/services/llm/llm.py +0 -195
- unrealon_driver/src/services/logger_service.py +0 -232
- unrealon_driver/src/services/metrics_service.py +0 -185
- unrealon_driver/src/services/scheduler_service.py +0 -489
- unrealon_driver/src/services/websocket_service.py +0 -362
- unrealon_driver/src/utils/__init__.py +0 -16
- unrealon_driver/src/utils/service_factory.py +0 -317
- unrealon_driver/src/utils/time_formatter.py +0 -338
- unrealon_llm/README.md +0 -44
- unrealon_llm/__init__.py +0 -26
- unrealon_llm/pyproject.toml +0 -154
- unrealon_llm/src/__init__.py +0 -228
- unrealon_llm/src/cli/__init__.py +0 -0
- unrealon_llm/src/core/__init__.py +0 -11
- unrealon_llm/src/core/smart_client.py +0 -438
- unrealon_llm/src/dto/__init__.py +0 -155
- unrealon_llm/src/dto/models/__init__.py +0 -0
- unrealon_llm/src/dto/models/config.py +0 -343
- unrealon_llm/src/dto/models/core.py +0 -328
- unrealon_llm/src/dto/models/enums.py +0 -123
- unrealon_llm/src/dto/models/html_analysis.py +0 -345
- unrealon_llm/src/dto/models/statistics.py +0 -473
- unrealon_llm/src/dto/models/translation.py +0 -383
- unrealon_llm/src/dto/models/type_conversion.py +0 -462
- unrealon_llm/src/dto/schemas/__init__.py +0 -0
- unrealon_llm/src/exceptions.py +0 -392
- unrealon_llm/src/llm_config/__init__.py +0 -20
- unrealon_llm/src/llm_config/logging_config.py +0 -178
- unrealon_llm/src/llm_logging/__init__.py +0 -42
- unrealon_llm/src/llm_logging/llm_events.py +0 -107
- unrealon_llm/src/llm_logging/llm_logger.py +0 -466
- unrealon_llm/src/managers/__init__.py +0 -15
- unrealon_llm/src/managers/cache_manager.py +0 -67
- unrealon_llm/src/managers/cost_manager.py +0 -107
- unrealon_llm/src/managers/request_manager.py +0 -298
- unrealon_llm/src/modules/__init__.py +0 -0
- unrealon_llm/src/modules/html_processor/__init__.py +0 -25
- unrealon_llm/src/modules/html_processor/base_processor.py +0 -415
- unrealon_llm/src/modules/html_processor/details_processor.py +0 -85
- unrealon_llm/src/modules/html_processor/listing_processor.py +0 -91
- unrealon_llm/src/modules/html_processor/models/__init__.py +0 -20
- unrealon_llm/src/modules/html_processor/models/processing_models.py +0 -40
- unrealon_llm/src/modules/html_processor/models/universal_model.py +0 -56
- unrealon_llm/src/modules/html_processor/processor.py +0 -102
- unrealon_llm/src/modules/llm/__init__.py +0 -0
- unrealon_llm/src/modules/translator/__init__.py +0 -0
- unrealon_llm/src/provider.py +0 -116
- unrealon_llm/src/utils/__init__.py +0 -95
- unrealon_llm/src/utils/common.py +0 -64
- unrealon_llm/src/utils/data_extractor.py +0 -188
- unrealon_llm/src/utils/html_cleaner.py +0 -767
- unrealon_llm/src/utils/language_detector.py +0 -308
- unrealon_llm/src/utils/models_cache.py +0 -592
- unrealon_llm/src/utils/smart_counter.py +0 -229
- unrealon_llm/src/utils/token_counter.py +0 -189
- unrealon_sdk/README.md +0 -25
- unrealon_sdk/__init__.py +0 -30
- unrealon_sdk/pyproject.toml +0 -231
- unrealon_sdk/src/__init__.py +0 -150
- unrealon_sdk/src/cli/__init__.py +0 -12
- unrealon_sdk/src/cli/commands/__init__.py +0 -22
- unrealon_sdk/src/cli/commands/benchmark.py +0 -42
- unrealon_sdk/src/cli/commands/diagnostics.py +0 -573
- unrealon_sdk/src/cli/commands/health.py +0 -46
- unrealon_sdk/src/cli/commands/integration.py +0 -498
- unrealon_sdk/src/cli/commands/reports.py +0 -43
- unrealon_sdk/src/cli/commands/security.py +0 -36
- unrealon_sdk/src/cli/commands/server.py +0 -483
- unrealon_sdk/src/cli/commands/servers.py +0 -56
- unrealon_sdk/src/cli/commands/tests.py +0 -55
- unrealon_sdk/src/cli/main.py +0 -126
- unrealon_sdk/src/cli/utils/reporter.py +0 -519
- unrealon_sdk/src/clients/openapi.yaml +0 -3347
- unrealon_sdk/src/clients/python_http/__init__.py +0 -3
- unrealon_sdk/src/clients/python_http/api_config.py +0 -228
- unrealon_sdk/src/clients/python_http/models/BaseModel.py +0 -12
- unrealon_sdk/src/clients/python_http/models/BroadcastDeliveryStats.py +0 -33
- unrealon_sdk/src/clients/python_http/models/BroadcastMessage.py +0 -17
- unrealon_sdk/src/clients/python_http/models/BroadcastMessageRequest.py +0 -35
- unrealon_sdk/src/clients/python_http/models/BroadcastPriority.py +0 -10
- unrealon_sdk/src/clients/python_http/models/BroadcastResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/BroadcastResultResponse.py +0 -33
- unrealon_sdk/src/clients/python_http/models/BroadcastTarget.py +0 -11
- unrealon_sdk/src/clients/python_http/models/ConnectionStats.py +0 -27
- unrealon_sdk/src/clients/python_http/models/ConnectionsResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/DeveloperMessageResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ErrorResponse.py +0 -25
- unrealon_sdk/src/clients/python_http/models/HTTPValidationError.py +0 -16
- unrealon_sdk/src/clients/python_http/models/HealthResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/HealthStatus.py +0 -33
- unrealon_sdk/src/clients/python_http/models/LogLevel.py +0 -10
- unrealon_sdk/src/clients/python_http/models/LoggingRequest.py +0 -27
- unrealon_sdk/src/clients/python_http/models/LoggingResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/MaintenanceMode.py +0 -9
- unrealon_sdk/src/clients/python_http/models/MaintenanceModeRequest.py +0 -33
- unrealon_sdk/src/clients/python_http/models/MaintenanceStatusResponse.py +0 -39
- unrealon_sdk/src/clients/python_http/models/ParserCommandRequest.py +0 -25
- unrealon_sdk/src/clients/python_http/models/ParserMessageResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/ParserRegistrationRequest.py +0 -28
- unrealon_sdk/src/clients/python_http/models/ParserRegistrationResponse.py +0 -25
- unrealon_sdk/src/clients/python_http/models/ParserType.py +0 -10
- unrealon_sdk/src/clients/python_http/models/ProxyBlockRequest.py +0 -19
- unrealon_sdk/src/clients/python_http/models/ProxyEndpointResponse.py +0 -20
- unrealon_sdk/src/clients/python_http/models/ProxyListResponse.py +0 -19
- unrealon_sdk/src/clients/python_http/models/ProxyProvider.py +0 -10
- unrealon_sdk/src/clients/python_http/models/ProxyPurchaseRequest.py +0 -25
- unrealon_sdk/src/clients/python_http/models/ProxyResponse.py +0 -47
- unrealon_sdk/src/clients/python_http/models/ProxyRotationRequest.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ProxyStatus.py +0 -10
- unrealon_sdk/src/clients/python_http/models/ProxyUsageRequest.py +0 -19
- unrealon_sdk/src/clients/python_http/models/ProxyUsageStatsResponse.py +0 -26
- unrealon_sdk/src/clients/python_http/models/ServiceRegistrationDto.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ServiceStatsResponse.py +0 -31
- unrealon_sdk/src/clients/python_http/models/SessionStartRequest.py +0 -23
- unrealon_sdk/src/clients/python_http/models/SuccessResponse.py +0 -25
- unrealon_sdk/src/clients/python_http/models/SystemNotificationResponse.py +0 -23
- unrealon_sdk/src/clients/python_http/models/ValidationError.py +0 -18
- unrealon_sdk/src/clients/python_http/models/ValidationErrorResponse.py +0 -21
- unrealon_sdk/src/clients/python_http/models/WebSocketMetrics.py +0 -21
- unrealon_sdk/src/clients/python_http/models/__init__.py +0 -44
- unrealon_sdk/src/clients/python_http/services/None_service.py +0 -35
- unrealon_sdk/src/clients/python_http/services/ParserManagement_service.py +0 -190
- unrealon_sdk/src/clients/python_http/services/ProxyManagement_service.py +0 -289
- unrealon_sdk/src/clients/python_http/services/SocketLogging_service.py +0 -187
- unrealon_sdk/src/clients/python_http/services/SystemHealth_service.py +0 -119
- unrealon_sdk/src/clients/python_http/services/WebSocketAPI_service.py +0 -198
- unrealon_sdk/src/clients/python_http/services/__init__.py +0 -0
- unrealon_sdk/src/clients/python_http/services/admin_service.py +0 -125
- unrealon_sdk/src/clients/python_http/services/async_None_service.py +0 -35
- unrealon_sdk/src/clients/python_http/services/async_ParserManagement_service.py +0 -190
- unrealon_sdk/src/clients/python_http/services/async_ProxyManagement_service.py +0 -289
- unrealon_sdk/src/clients/python_http/services/async_SocketLogging_service.py +0 -189
- unrealon_sdk/src/clients/python_http/services/async_SystemHealth_service.py +0 -123
- unrealon_sdk/src/clients/python_http/services/async_WebSocketAPI_service.py +0 -200
- unrealon_sdk/src/clients/python_http/services/async_admin_service.py +0 -125
- unrealon_sdk/src/clients/python_websocket/__init__.py +0 -28
- unrealon_sdk/src/clients/python_websocket/client.py +0 -490
- unrealon_sdk/src/clients/python_websocket/events.py +0 -732
- unrealon_sdk/src/clients/python_websocket/example.py +0 -136
- unrealon_sdk/src/clients/python_websocket/types.py +0 -871
- unrealon_sdk/src/core/__init__.py +0 -64
- unrealon_sdk/src/core/client.py +0 -556
- unrealon_sdk/src/core/config.py +0 -465
- unrealon_sdk/src/core/exceptions.py +0 -239
- unrealon_sdk/src/core/metadata.py +0 -191
- unrealon_sdk/src/core/models.py +0 -142
- unrealon_sdk/src/core/types.py +0 -68
- unrealon_sdk/src/dto/__init__.py +0 -268
- unrealon_sdk/src/dto/authentication.py +0 -108
- unrealon_sdk/src/dto/cache.py +0 -208
- unrealon_sdk/src/dto/common.py +0 -19
- unrealon_sdk/src/dto/concurrency.py +0 -393
- unrealon_sdk/src/dto/events.py +0 -108
- unrealon_sdk/src/dto/health.py +0 -339
- unrealon_sdk/src/dto/load_balancing.py +0 -336
- unrealon_sdk/src/dto/logging.py +0 -230
- unrealon_sdk/src/dto/performance.py +0 -165
- unrealon_sdk/src/dto/rate_limiting.py +0 -295
- unrealon_sdk/src/dto/resource_pooling.py +0 -128
- unrealon_sdk/src/dto/structured_logging.py +0 -112
- unrealon_sdk/src/dto/task_scheduling.py +0 -121
- unrealon_sdk/src/dto/websocket.py +0 -55
- unrealon_sdk/src/enterprise/__init__.py +0 -59
- unrealon_sdk/src/enterprise/authentication.py +0 -401
- unrealon_sdk/src/enterprise/cache_manager.py +0 -578
- unrealon_sdk/src/enterprise/error_recovery.py +0 -494
- unrealon_sdk/src/enterprise/event_system.py +0 -549
- unrealon_sdk/src/enterprise/health_monitor.py +0 -747
- unrealon_sdk/src/enterprise/load_balancer.py +0 -964
- unrealon_sdk/src/enterprise/logging/__init__.py +0 -68
- unrealon_sdk/src/enterprise/logging/cleanup.py +0 -156
- unrealon_sdk/src/enterprise/logging/development.py +0 -744
- unrealon_sdk/src/enterprise/logging/service.py +0 -410
- unrealon_sdk/src/enterprise/multithreading_manager.py +0 -853
- unrealon_sdk/src/enterprise/performance_monitor.py +0 -539
- unrealon_sdk/src/enterprise/proxy_manager.py +0 -696
- unrealon_sdk/src/enterprise/rate_limiter.py +0 -652
- unrealon_sdk/src/enterprise/resource_pool.py +0 -763
- unrealon_sdk/src/enterprise/task_scheduler.py +0 -709
- unrealon_sdk/src/internal/__init__.py +0 -10
- unrealon_sdk/src/internal/command_router.py +0 -497
- unrealon_sdk/src/internal/connection_manager.py +0 -397
- unrealon_sdk/src/internal/http_client.py +0 -446
- unrealon_sdk/src/internal/websocket_client.py +0 -420
- unrealon_sdk/src/provider.py +0 -471
- unrealon_sdk/src/utils.py +0 -234
- /unrealon_browser/{src/cli → cli}/__init__.py +0 -0
- /unrealon_browser/{src/cli → cli}/interactive_mode.py +0 -0
- /unrealon_browser/{src/cli → cli}/main.py +0 -0
- /unrealon_browser/{src/core → core}/__init__.py +0 -0
- /unrealon_browser/{src/dto → dto}/__init__.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/config.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/core.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/dataclasses.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/detection.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/enums.py +0 -0
- /unrealon_browser/{src/dto → dto}/models/statistics.py +0 -0
- /unrealon_browser/{src/managers → managers}/__init__.py +0 -0
- /unrealon_browser/{src/managers → managers}/stealth.py +0 -0
|
@@ -1,494 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Error Recovery System - Layer 2 Connection Management Component
|
|
3
|
-
|
|
4
|
-
Enterprise-grade error recovery with exponential backoff, circuit breakers,
|
|
5
|
-
and automatic retry mechanisms. Provides resilient connection management
|
|
6
|
-
for WebSocket and HTTP clients with intelligent failure detection and recovery.
|
|
7
|
-
|
|
8
|
-
Features:
|
|
9
|
-
- Exponential backoff with jitter for retry timing
|
|
10
|
-
- Circuit breaker pattern for fault tolerance
|
|
11
|
-
- Automatic reconnection with configurable limits
|
|
12
|
-
- Health monitoring and recovery metrics
|
|
13
|
-
- Error classification and appropriate response strategies
|
|
14
|
-
- Integration with development logging for observability
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
import asyncio
|
|
18
|
-
import logging
|
|
19
|
-
import time
|
|
20
|
-
import random
|
|
21
|
-
from typing import Optional, Dict, List, Any, Callable, Awaitable, Union
|
|
22
|
-
from datetime import datetime, timezone
|
|
23
|
-
from enum import Enum
|
|
24
|
-
from dataclasses import dataclass, field
|
|
25
|
-
import traceback
|
|
26
|
-
|
|
27
|
-
# Pydantic v2 for all data models
|
|
28
|
-
from pydantic import BaseModel, Field, ConfigDict
|
|
29
|
-
|
|
30
|
-
# Auto-generated models for error handling
|
|
31
|
-
from unrealon_sdk.src.clients.python_http.models import ErrorResponse
|
|
32
|
-
|
|
33
|
-
# Core SDK components
|
|
34
|
-
from unrealon_sdk.src.core.config import AdapterConfig
|
|
35
|
-
from unrealon_sdk.src.core.exceptions import ConnectionError, LoggingError
|
|
36
|
-
from unrealon_sdk.src.utils import generate_correlation_id
|
|
37
|
-
|
|
38
|
-
# DTO models for error recovery
|
|
39
|
-
from unrealon_sdk.src.dto.logging import SDKEventType, SDKSeverity
|
|
40
|
-
|
|
41
|
-
# Development logging
|
|
42
|
-
from typing import TYPE_CHECKING
|
|
43
|
-
if TYPE_CHECKING:
|
|
44
|
-
from unrealon_sdk.src.enterprise.logging import DevelopmentLogger
|
|
45
|
-
|
|
46
|
-
logger = logging.getLogger(__name__)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class ErrorType(str, Enum):
|
|
50
|
-
"""Types of errors that can trigger recovery mechanisms."""
|
|
51
|
-
|
|
52
|
-
CONNECTION_TIMEOUT = "connection_timeout"
|
|
53
|
-
CONNECTION_REFUSED = "connection_refused"
|
|
54
|
-
NETWORK_UNREACHABLE = "network_unreachable"
|
|
55
|
-
AUTHENTICATION_FAILED = "authentication_failed"
|
|
56
|
-
SERVER_ERROR = "server_error"
|
|
57
|
-
RATE_LIMITED = "rate_limited"
|
|
58
|
-
WEBSOCKET_CLOSED = "websocket_closed"
|
|
59
|
-
HTTP_CLIENT_ERROR = "http_client_error"
|
|
60
|
-
UNKNOWN_ERROR = "unknown_error"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class RecoveryStrategy(str, Enum):
|
|
64
|
-
"""Recovery strategies for different error types."""
|
|
65
|
-
|
|
66
|
-
IMMEDIATE_RETRY = "immediate_retry"
|
|
67
|
-
EXPONENTIAL_BACKOFF = "exponential_backoff"
|
|
68
|
-
LINEAR_BACKOFF = "linear_backoff"
|
|
69
|
-
CIRCUIT_BREAKER = "circuit_breaker"
|
|
70
|
-
NO_RETRY = "no_retry"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class CircuitBreakerState(str, Enum):
|
|
74
|
-
"""Circuit breaker states."""
|
|
75
|
-
|
|
76
|
-
CLOSED = "closed" # Normal operation
|
|
77
|
-
OPEN = "open" # Failing, reject requests
|
|
78
|
-
HALF_OPEN = "half_open" # Testing if service recovered
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@dataclass
|
|
82
|
-
class RetryConfig:
|
|
83
|
-
"""Configuration for retry behavior."""
|
|
84
|
-
|
|
85
|
-
max_retries: int = 5
|
|
86
|
-
base_delay: float = 1.0 # Base delay in seconds
|
|
87
|
-
max_delay: float = 60.0 # Maximum delay in seconds
|
|
88
|
-
exponential_base: float = 2.0
|
|
89
|
-
jitter_factor: float = 0.1 # Add randomness to avoid thundering herd
|
|
90
|
-
timeout: float = 30.0 # Operation timeout
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@dataclass
|
|
94
|
-
class CircuitBreakerConfig:
|
|
95
|
-
"""Configuration for circuit breaker behavior."""
|
|
96
|
-
|
|
97
|
-
failure_threshold: int = 5 # Failures before opening
|
|
98
|
-
recovery_timeout: float = 30.0 # Seconds before attempting recovery
|
|
99
|
-
success_threshold: int = 3 # Successes needed to close circuit
|
|
100
|
-
monitoring_window: float = 60.0 # Time window for failure counting
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
class ErrorRecoveryMetrics(BaseModel):
|
|
104
|
-
"""Metrics for error recovery operations."""
|
|
105
|
-
|
|
106
|
-
model_config = ConfigDict(extra="forbid")
|
|
107
|
-
|
|
108
|
-
total_errors: int = Field(default=0, description="Total errors encountered")
|
|
109
|
-
errors_by_type: Dict[str, int] = Field(default_factory=dict, description="Errors by type")
|
|
110
|
-
total_retries: int = Field(default=0, description="Total retry attempts")
|
|
111
|
-
successful_recoveries: int = Field(default=0, description="Successful recoveries")
|
|
112
|
-
failed_recoveries: int = Field(default=0, description="Failed recoveries")
|
|
113
|
-
circuit_breaker_trips: int = Field(default=0, description="Circuit breaker activations")
|
|
114
|
-
average_recovery_time: float = Field(default=0.0, description="Average recovery time in seconds")
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
class ErrorRecoveryEvent(BaseModel):
|
|
118
|
-
"""Event model for error recovery operations."""
|
|
119
|
-
|
|
120
|
-
model_config = ConfigDict(extra="forbid")
|
|
121
|
-
|
|
122
|
-
event_id: str = Field(default_factory=generate_correlation_id, description="Unique event ID")
|
|
123
|
-
timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), description="Event timestamp")
|
|
124
|
-
error_type: ErrorType = Field(..., description="Type of error")
|
|
125
|
-
strategy: RecoveryStrategy = Field(..., description="Recovery strategy used")
|
|
126
|
-
attempt_number: int = Field(..., description="Retry attempt number")
|
|
127
|
-
delay_seconds: float = Field(..., description="Delay before retry")
|
|
128
|
-
success: bool = Field(..., description="Whether recovery was successful")
|
|
129
|
-
error_details: Optional[Dict[str, Any]] = Field(default=None, description="Additional error details")
|
|
130
|
-
duration_ms: Optional[float] = Field(default=None, description="Recovery operation duration")
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
class CircuitBreaker:
|
|
134
|
-
"""Circuit breaker implementation for fault tolerance."""
|
|
135
|
-
|
|
136
|
-
def __init__(self, config: CircuitBreakerConfig, name: str = "default"):
|
|
137
|
-
self.config = config
|
|
138
|
-
self.name = name
|
|
139
|
-
self.state = CircuitBreakerState.CLOSED
|
|
140
|
-
self.failure_count = 0
|
|
141
|
-
self.success_count = 0
|
|
142
|
-
self.last_failure_time: Optional[float] = None
|
|
143
|
-
self.failure_times: List[float] = []
|
|
144
|
-
|
|
145
|
-
def can_execute(self) -> bool:
|
|
146
|
-
"""Check if operation can be executed based on circuit breaker state."""
|
|
147
|
-
now = time.time()
|
|
148
|
-
|
|
149
|
-
# Clean old failures outside monitoring window
|
|
150
|
-
cutoff_time = now - self.config.monitoring_window
|
|
151
|
-
self.failure_times = [t for t in self.failure_times if t > cutoff_time]
|
|
152
|
-
self.failure_count = len(self.failure_times)
|
|
153
|
-
|
|
154
|
-
if self.state == CircuitBreakerState.CLOSED:
|
|
155
|
-
return True
|
|
156
|
-
|
|
157
|
-
if self.state == CircuitBreakerState.OPEN:
|
|
158
|
-
# Check if recovery timeout has passed
|
|
159
|
-
if (self.last_failure_time and
|
|
160
|
-
now - self.last_failure_time >= self.config.recovery_timeout):
|
|
161
|
-
self.state = CircuitBreakerState.HALF_OPEN
|
|
162
|
-
self.success_count = 0
|
|
163
|
-
return True
|
|
164
|
-
return False
|
|
165
|
-
|
|
166
|
-
# self.state == CircuitBreakerState.HALF_OPEN
|
|
167
|
-
return True
|
|
168
|
-
|
|
169
|
-
def record_success(self) -> None:
|
|
170
|
-
"""Record a successful operation."""
|
|
171
|
-
if self.state == CircuitBreakerState.HALF_OPEN:
|
|
172
|
-
self.success_count += 1
|
|
173
|
-
if self.success_count >= self.config.success_threshold:
|
|
174
|
-
self.state = CircuitBreakerState.CLOSED
|
|
175
|
-
self.failure_count = 0
|
|
176
|
-
self.failure_times.clear()
|
|
177
|
-
elif self.state == CircuitBreakerState.CLOSED:
|
|
178
|
-
# Reset failure count on success
|
|
179
|
-
self.failure_count = max(0, self.failure_count - 1)
|
|
180
|
-
|
|
181
|
-
def record_failure(self) -> None:
|
|
182
|
-
"""Record a failed operation."""
|
|
183
|
-
now = time.time()
|
|
184
|
-
self.failure_times.append(now)
|
|
185
|
-
self.failure_count += 1
|
|
186
|
-
self.last_failure_time = now
|
|
187
|
-
|
|
188
|
-
if self.state == CircuitBreakerState.CLOSED:
|
|
189
|
-
if self.failure_count >= self.config.failure_threshold:
|
|
190
|
-
self.state = CircuitBreakerState.OPEN
|
|
191
|
-
elif self.state == CircuitBreakerState.HALF_OPEN:
|
|
192
|
-
self.state = CircuitBreakerState.OPEN
|
|
193
|
-
self.success_count = 0
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
class ErrorRecoverySystem:
|
|
197
|
-
"""
|
|
198
|
-
Enterprise-grade error recovery system with exponential backoff and circuit breakers.
|
|
199
|
-
|
|
200
|
-
Provides intelligent error handling and automatic recovery for connection management
|
|
201
|
-
components including WebSocket and HTTP clients.
|
|
202
|
-
"""
|
|
203
|
-
|
|
204
|
-
def __init__(
|
|
205
|
-
self,
|
|
206
|
-
config: AdapterConfig,
|
|
207
|
-
retry_config: Optional[RetryConfig] = None,
|
|
208
|
-
circuit_breaker_config: Optional[CircuitBreakerConfig] = None,
|
|
209
|
-
dev_logger: Optional["DevelopmentLogger"] = None,
|
|
210
|
-
):
|
|
211
|
-
"""Initialize error recovery system."""
|
|
212
|
-
self.config = config
|
|
213
|
-
self.retry_config = retry_config or RetryConfig()
|
|
214
|
-
self.circuit_breaker_config = circuit_breaker_config or CircuitBreakerConfig()
|
|
215
|
-
self.dev_logger = dev_logger
|
|
216
|
-
|
|
217
|
-
# Circuit breakers for different components
|
|
218
|
-
self.circuit_breakers: Dict[str, CircuitBreaker] = {}
|
|
219
|
-
|
|
220
|
-
# Metrics
|
|
221
|
-
self.metrics = ErrorRecoveryMetrics()
|
|
222
|
-
|
|
223
|
-
# Error type to strategy mapping
|
|
224
|
-
self.error_strategies: Dict[ErrorType, RecoveryStrategy] = {
|
|
225
|
-
ErrorType.CONNECTION_TIMEOUT: RecoveryStrategy.EXPONENTIAL_BACKOFF,
|
|
226
|
-
ErrorType.CONNECTION_REFUSED: RecoveryStrategy.EXPONENTIAL_BACKOFF,
|
|
227
|
-
ErrorType.NETWORK_UNREACHABLE: RecoveryStrategy.EXPONENTIAL_BACKOFF,
|
|
228
|
-
ErrorType.AUTHENTICATION_FAILED: RecoveryStrategy.NO_RETRY,
|
|
229
|
-
ErrorType.SERVER_ERROR: RecoveryStrategy.EXPONENTIAL_BACKOFF,
|
|
230
|
-
ErrorType.RATE_LIMITED: RecoveryStrategy.LINEAR_BACKOFF,
|
|
231
|
-
ErrorType.WEBSOCKET_CLOSED: RecoveryStrategy.EXPONENTIAL_BACKOFF,
|
|
232
|
-
ErrorType.HTTP_CLIENT_ERROR: RecoveryStrategy.CIRCUIT_BREAKER,
|
|
233
|
-
ErrorType.UNKNOWN_ERROR: RecoveryStrategy.EXPONENTIAL_BACKOFF,
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
self._log_info("Error recovery system initialized")
|
|
237
|
-
|
|
238
|
-
def get_circuit_breaker(self, component_name: str) -> CircuitBreaker:
|
|
239
|
-
"""Get or create circuit breaker for component."""
|
|
240
|
-
if component_name not in self.circuit_breakers:
|
|
241
|
-
self.circuit_breakers[component_name] = CircuitBreaker(
|
|
242
|
-
self.circuit_breaker_config,
|
|
243
|
-
component_name
|
|
244
|
-
)
|
|
245
|
-
return self.circuit_breakers[component_name]
|
|
246
|
-
|
|
247
|
-
async def execute_with_recovery(
|
|
248
|
-
self,
|
|
249
|
-
operation: Callable[[], Awaitable[Any]],
|
|
250
|
-
component_name: str,
|
|
251
|
-
operation_name: str,
|
|
252
|
-
error_classifier: Optional[Callable[[Exception], ErrorType]] = None,
|
|
253
|
-
) -> Any:
|
|
254
|
-
"""
|
|
255
|
-
Execute operation with automatic error recovery.
|
|
256
|
-
|
|
257
|
-
Args:
|
|
258
|
-
operation: Async operation to execute
|
|
259
|
-
component_name: Name of component (for circuit breaker)
|
|
260
|
-
operation_name: Name of operation (for logging)
|
|
261
|
-
error_classifier: Function to classify exceptions into ErrorType
|
|
262
|
-
|
|
263
|
-
Returns:
|
|
264
|
-
Result of successful operation
|
|
265
|
-
|
|
266
|
-
Raises:
|
|
267
|
-
Exception: If all recovery attempts fail
|
|
268
|
-
"""
|
|
269
|
-
circuit_breaker = self.get_circuit_breaker(component_name)
|
|
270
|
-
last_exception: Optional[Exception] = None
|
|
271
|
-
|
|
272
|
-
for attempt in range(self.retry_config.max_retries + 1):
|
|
273
|
-
# Check circuit breaker
|
|
274
|
-
if not circuit_breaker.can_execute():
|
|
275
|
-
self._log_error(
|
|
276
|
-
f"Circuit breaker open for {component_name}, skipping {operation_name}",
|
|
277
|
-
error_type=ErrorType.UNKNOWN_ERROR,
|
|
278
|
-
)
|
|
279
|
-
self.metrics.circuit_breaker_trips += 1
|
|
280
|
-
raise ConnectionError(f"Circuit breaker open for {component_name}")
|
|
281
|
-
|
|
282
|
-
try:
|
|
283
|
-
start_time = time.time()
|
|
284
|
-
|
|
285
|
-
# Execute operation with timeout
|
|
286
|
-
result = await asyncio.wait_for(
|
|
287
|
-
operation(),
|
|
288
|
-
timeout=self.retry_config.timeout
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
duration_ms = (time.time() - start_time) * 1000
|
|
292
|
-
|
|
293
|
-
# Record success
|
|
294
|
-
circuit_breaker.record_success()
|
|
295
|
-
|
|
296
|
-
if attempt > 0:
|
|
297
|
-
self.metrics.successful_recoveries += 1
|
|
298
|
-
self._log_info(
|
|
299
|
-
f"Recovery successful for {operation_name} after {attempt} attempts",
|
|
300
|
-
duration_ms=duration_ms
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
return result
|
|
304
|
-
|
|
305
|
-
except Exception as e:
|
|
306
|
-
last_exception = e
|
|
307
|
-
self.metrics.total_errors += 1
|
|
308
|
-
|
|
309
|
-
# Classify error
|
|
310
|
-
error_type = error_classifier(e) if error_classifier else self._classify_error(e)
|
|
311
|
-
self.metrics.errors_by_type[error_type.value] = (
|
|
312
|
-
self.metrics.errors_by_type.get(error_type.value, 0) + 1
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
# Record failure in circuit breaker
|
|
316
|
-
circuit_breaker.record_failure()
|
|
317
|
-
|
|
318
|
-
# Determine if we should retry
|
|
319
|
-
strategy = self.error_strategies.get(error_type, RecoveryStrategy.EXPONENTIAL_BACKOFF)
|
|
320
|
-
|
|
321
|
-
if strategy == RecoveryStrategy.NO_RETRY or attempt >= self.retry_config.max_retries:
|
|
322
|
-
self.metrics.failed_recoveries += 1
|
|
323
|
-
self._log_error(
|
|
324
|
-
f"Recovery failed for {operation_name} after {attempt + 1} attempts",
|
|
325
|
-
error_type=error_type,
|
|
326
|
-
exception=e
|
|
327
|
-
)
|
|
328
|
-
raise e
|
|
329
|
-
|
|
330
|
-
# Calculate delay and wait
|
|
331
|
-
delay = self._calculate_delay(attempt, strategy)
|
|
332
|
-
|
|
333
|
-
self._log_recovery_event(
|
|
334
|
-
error_type=error_type,
|
|
335
|
-
strategy=strategy,
|
|
336
|
-
attempt_number=attempt + 1,
|
|
337
|
-
delay_seconds=delay,
|
|
338
|
-
success=False,
|
|
339
|
-
error_details={"exception": str(e), "component": component_name}
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
self.metrics.total_retries += 1
|
|
343
|
-
|
|
344
|
-
if delay > 0:
|
|
345
|
-
await asyncio.sleep(delay)
|
|
346
|
-
|
|
347
|
-
# Should not reach here, but just in case
|
|
348
|
-
if last_exception:
|
|
349
|
-
raise last_exception
|
|
350
|
-
else:
|
|
351
|
-
raise ConnectionError(f"Failed to execute {operation_name} after all retries")
|
|
352
|
-
|
|
353
|
-
def _classify_error(self, error: Exception) -> ErrorType:
|
|
354
|
-
"""Classify exception into ErrorType for recovery strategy selection."""
|
|
355
|
-
error_str = str(error).lower()
|
|
356
|
-
error_type_name = type(error).__name__.lower()
|
|
357
|
-
|
|
358
|
-
if "timeout" in error_str or "timeout" in error_type_name:
|
|
359
|
-
return ErrorType.CONNECTION_TIMEOUT
|
|
360
|
-
elif "connection refused" in error_str or "refused" in error_str:
|
|
361
|
-
return ErrorType.CONNECTION_REFUSED
|
|
362
|
-
elif "network" in error_str or "unreachable" in error_str:
|
|
363
|
-
return ErrorType.NETWORK_UNREACHABLE
|
|
364
|
-
elif "auth" in error_str or "unauthorized" in error_str:
|
|
365
|
-
return ErrorType.AUTHENTICATION_FAILED
|
|
366
|
-
elif "server error" in error_str or "500" in error_str:
|
|
367
|
-
return ErrorType.SERVER_ERROR
|
|
368
|
-
elif "rate" in error_str or "429" in error_str:
|
|
369
|
-
return ErrorType.RATE_LIMITED
|
|
370
|
-
elif "websocket" in error_str or "socket" in error_str:
|
|
371
|
-
return ErrorType.WEBSOCKET_CLOSED
|
|
372
|
-
elif "http" in error_str:
|
|
373
|
-
return ErrorType.HTTP_CLIENT_ERROR
|
|
374
|
-
else:
|
|
375
|
-
return ErrorType.UNKNOWN_ERROR
|
|
376
|
-
|
|
377
|
-
def _calculate_delay(self, attempt: int, strategy: RecoveryStrategy) -> float:
|
|
378
|
-
"""Calculate delay for retry attempt based on strategy."""
|
|
379
|
-
if strategy == RecoveryStrategy.IMMEDIATE_RETRY:
|
|
380
|
-
return 0.0
|
|
381
|
-
elif strategy == RecoveryStrategy.LINEAR_BACKOFF:
|
|
382
|
-
delay = self.retry_config.base_delay * (attempt + 1)
|
|
383
|
-
elif strategy == RecoveryStrategy.EXPONENTIAL_BACKOFF:
|
|
384
|
-
delay = self.retry_config.base_delay * (self.retry_config.exponential_base ** attempt)
|
|
385
|
-
else:
|
|
386
|
-
delay = self.retry_config.base_delay
|
|
387
|
-
|
|
388
|
-
# Apply jitter to avoid thundering herd
|
|
389
|
-
jitter = delay * self.retry_config.jitter_factor * (2 * random.random() - 1)
|
|
390
|
-
delay += jitter
|
|
391
|
-
|
|
392
|
-
# Clamp to max delay
|
|
393
|
-
return min(delay, self.retry_config.max_delay)
|
|
394
|
-
|
|
395
|
-
def _log_recovery_event(
|
|
396
|
-
self,
|
|
397
|
-
error_type: ErrorType,
|
|
398
|
-
strategy: RecoveryStrategy,
|
|
399
|
-
attempt_number: int,
|
|
400
|
-
delay_seconds: float,
|
|
401
|
-
success: bool,
|
|
402
|
-
error_details: Optional[Dict[str, Any]] = None,
|
|
403
|
-
) -> None:
|
|
404
|
-
"""Log recovery event for monitoring and debugging."""
|
|
405
|
-
event = ErrorRecoveryEvent(
|
|
406
|
-
error_type=error_type,
|
|
407
|
-
strategy=strategy,
|
|
408
|
-
attempt_number=attempt_number,
|
|
409
|
-
delay_seconds=delay_seconds,
|
|
410
|
-
success=success,
|
|
411
|
-
error_details=error_details,
|
|
412
|
-
)
|
|
413
|
-
|
|
414
|
-
self._log_info(
|
|
415
|
-
f"Error recovery attempt {attempt_number}: {error_type.value} -> {strategy.value}",
|
|
416
|
-
details={"recovery_event": event.model_dump()}
|
|
417
|
-
)
|
|
418
|
-
|
|
419
|
-
def _log_info(self, message: str, **kwargs: Any) -> None:
|
|
420
|
-
"""Log info message with development logger if available."""
|
|
421
|
-
if self.dev_logger:
|
|
422
|
-
self.dev_logger.log_info(
|
|
423
|
-
SDKEventType.ERROR_RECOVERY_STARTED,
|
|
424
|
-
message,
|
|
425
|
-
**kwargs
|
|
426
|
-
)
|
|
427
|
-
else:
|
|
428
|
-
logger.info(message)
|
|
429
|
-
|
|
430
|
-
def _log_error(
|
|
431
|
-
self,
|
|
432
|
-
message: str,
|
|
433
|
-
error_type: ErrorType,
|
|
434
|
-
exception: Optional[Exception] = None,
|
|
435
|
-
**kwargs: Any
|
|
436
|
-
) -> None:
|
|
437
|
-
"""Log error message with development logger if available."""
|
|
438
|
-
if self.dev_logger:
|
|
439
|
-
self.dev_logger.log_error(
|
|
440
|
-
SDKEventType.ERROR_RECOVERY_FAILED,
|
|
441
|
-
message,
|
|
442
|
-
exception=exception,
|
|
443
|
-
details={"error_type": error_type.value},
|
|
444
|
-
**kwargs
|
|
445
|
-
)
|
|
446
|
-
else:
|
|
447
|
-
logger.error(message, exc_info=exception)
|
|
448
|
-
|
|
449
|
-
def get_metrics(self) -> ErrorRecoveryMetrics:
|
|
450
|
-
"""Get current error recovery metrics."""
|
|
451
|
-
return self.metrics
|
|
452
|
-
|
|
453
|
-
def get_circuit_breaker_status(self) -> Dict[str, Dict[str, Any]]:
|
|
454
|
-
"""Get status of all circuit breakers."""
|
|
455
|
-
return {
|
|
456
|
-
name: {
|
|
457
|
-
"state": breaker.state.value,
|
|
458
|
-
"failure_count": breaker.failure_count,
|
|
459
|
-
"success_count": breaker.success_count,
|
|
460
|
-
"last_failure_time": breaker.last_failure_time,
|
|
461
|
-
}
|
|
462
|
-
for name, breaker in self.circuit_breakers.items()
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
def reset_circuit_breaker(self, component_name: str) -> bool:
|
|
466
|
-
"""Manually reset circuit breaker for component."""
|
|
467
|
-
if component_name in self.circuit_breakers:
|
|
468
|
-
breaker = self.circuit_breakers[component_name]
|
|
469
|
-
breaker.state = CircuitBreakerState.CLOSED
|
|
470
|
-
breaker.failure_count = 0
|
|
471
|
-
breaker.success_count = 0
|
|
472
|
-
breaker.failure_times.clear()
|
|
473
|
-
|
|
474
|
-
self._log_info(f"Circuit breaker reset for {component_name}")
|
|
475
|
-
return True
|
|
476
|
-
return False
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
__all__ = [
|
|
480
|
-
# Main class
|
|
481
|
-
"ErrorRecoverySystem",
|
|
482
|
-
# Enums
|
|
483
|
-
"ErrorType",
|
|
484
|
-
"RecoveryStrategy",
|
|
485
|
-
"CircuitBreakerState",
|
|
486
|
-
# Configuration
|
|
487
|
-
"RetryConfig",
|
|
488
|
-
"CircuitBreakerConfig",
|
|
489
|
-
# Models
|
|
490
|
-
"ErrorRecoveryMetrics",
|
|
491
|
-
"ErrorRecoveryEvent",
|
|
492
|
-
# Circuit breaker
|
|
493
|
-
"CircuitBreaker",
|
|
494
|
-
]
|