unrealon 1.0.9__py3-none-any.whl → 1.1.0__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.
Files changed (302) hide show
  1. unrealon/__init__.py +23 -21
  2. unrealon-1.1.0.dist-info/METADATA +164 -0
  3. unrealon-1.1.0.dist-info/RECORD +82 -0
  4. {unrealon-1.0.9.dist-info → unrealon-1.1.0.dist-info}/WHEEL +1 -1
  5. unrealon-1.1.0.dist-info/entry_points.txt +9 -0
  6. {unrealon-1.0.9.dist-info → unrealon-1.1.0.dist-info/licenses}/LICENSE +1 -1
  7. unrealon_bridge/__init__.py +114 -0
  8. unrealon_bridge/cli.py +316 -0
  9. unrealon_bridge/client/__init__.py +93 -0
  10. unrealon_bridge/client/base.py +78 -0
  11. unrealon_bridge/client/commands.py +89 -0
  12. unrealon_bridge/client/connection.py +90 -0
  13. unrealon_bridge/client/events.py +65 -0
  14. unrealon_bridge/client/health.py +38 -0
  15. unrealon_bridge/client/html_parser.py +146 -0
  16. unrealon_bridge/client/logging.py +139 -0
  17. unrealon_bridge/client/proxy.py +70 -0
  18. unrealon_bridge/client/scheduler.py +450 -0
  19. unrealon_bridge/client/session.py +70 -0
  20. unrealon_bridge/configs/__init__.py +14 -0
  21. unrealon_bridge/configs/bridge_config.py +212 -0
  22. unrealon_bridge/configs/bridge_config.yaml +39 -0
  23. unrealon_bridge/models/__init__.py +138 -0
  24. unrealon_bridge/models/base.py +28 -0
  25. unrealon_bridge/models/command.py +41 -0
  26. unrealon_bridge/models/events.py +40 -0
  27. unrealon_bridge/models/html_parser.py +79 -0
  28. unrealon_bridge/models/logging.py +55 -0
  29. unrealon_bridge/models/parser.py +63 -0
  30. unrealon_bridge/models/proxy.py +41 -0
  31. unrealon_bridge/models/requests.py +95 -0
  32. unrealon_bridge/models/responses.py +88 -0
  33. unrealon_bridge/models/scheduler.py +592 -0
  34. unrealon_bridge/models/session.py +28 -0
  35. unrealon_bridge/server/__init__.py +91 -0
  36. unrealon_bridge/server/base.py +171 -0
  37. unrealon_bridge/server/handlers/__init__.py +23 -0
  38. unrealon_bridge/server/handlers/command.py +110 -0
  39. unrealon_bridge/server/handlers/html_parser.py +139 -0
  40. unrealon_bridge/server/handlers/logging.py +95 -0
  41. unrealon_bridge/server/handlers/parser.py +95 -0
  42. unrealon_bridge/server/handlers/proxy.py +75 -0
  43. unrealon_bridge/server/handlers/scheduler.py +545 -0
  44. unrealon_bridge/server/handlers/session.py +66 -0
  45. unrealon_browser/__init__.py +61 -18
  46. unrealon_browser/{src/cli → cli}/browser_cli.py +6 -13
  47. unrealon_browser/{src/cli → cli}/cookies_cli.py +5 -1
  48. unrealon_browser/{src/core → core}/browser_manager.py +2 -2
  49. unrealon_browser/{src/managers → managers}/captcha.py +1 -1
  50. unrealon_browser/{src/managers → managers}/cookies.py +1 -1
  51. unrealon_browser/managers/logger_bridge.py +231 -0
  52. unrealon_browser/{src/managers → managers}/profile.py +1 -1
  53. unrealon_driver/__init__.py +73 -19
  54. unrealon_driver/browser/__init__.py +8 -0
  55. unrealon_driver/browser/config.py +74 -0
  56. unrealon_driver/browser/manager.py +416 -0
  57. unrealon_driver/exceptions.py +28 -0
  58. unrealon_driver/parser/__init__.py +55 -0
  59. unrealon_driver/parser/cli_manager.py +141 -0
  60. unrealon_driver/parser/daemon_manager.py +227 -0
  61. unrealon_driver/parser/managers/__init__.py +46 -0
  62. unrealon_driver/parser/managers/browser.py +51 -0
  63. unrealon_driver/parser/managers/config.py +281 -0
  64. unrealon_driver/parser/managers/error.py +412 -0
  65. unrealon_driver/parser/managers/html.py +732 -0
  66. unrealon_driver/parser/managers/logging.py +609 -0
  67. unrealon_driver/parser/managers/result.py +321 -0
  68. unrealon_driver/parser/parser_manager.py +628 -0
  69. unrealon/sdk_config.py +0 -88
  70. unrealon-1.0.9.dist-info/METADATA +0 -810
  71. unrealon-1.0.9.dist-info/RECORD +0 -246
  72. unrealon_browser/pyproject.toml +0 -182
  73. unrealon_browser/src/__init__.py +0 -62
  74. unrealon_browser/src/managers/logger_bridge.py +0 -395
  75. unrealon_driver/README.md +0 -204
  76. unrealon_driver/pyproject.toml +0 -187
  77. unrealon_driver/src/__init__.py +0 -90
  78. unrealon_driver/src/cli/__init__.py +0 -10
  79. unrealon_driver/src/cli/main.py +0 -66
  80. unrealon_driver/src/cli/simple.py +0 -510
  81. unrealon_driver/src/config/__init__.py +0 -11
  82. unrealon_driver/src/config/auto_config.py +0 -478
  83. unrealon_driver/src/core/__init__.py +0 -18
  84. unrealon_driver/src/core/exceptions.py +0 -289
  85. unrealon_driver/src/core/parser.py +0 -638
  86. unrealon_driver/src/dto/__init__.py +0 -66
  87. unrealon_driver/src/dto/cli.py +0 -119
  88. unrealon_driver/src/dto/config.py +0 -18
  89. unrealon_driver/src/dto/events.py +0 -237
  90. unrealon_driver/src/dto/execution.py +0 -313
  91. unrealon_driver/src/dto/services.py +0 -311
  92. unrealon_driver/src/execution/__init__.py +0 -23
  93. unrealon_driver/src/execution/daemon_mode.py +0 -317
  94. unrealon_driver/src/execution/interactive_mode.py +0 -88
  95. unrealon_driver/src/execution/modes.py +0 -45
  96. unrealon_driver/src/execution/scheduled_mode.py +0 -209
  97. unrealon_driver/src/execution/test_mode.py +0 -250
  98. unrealon_driver/src/logging/__init__.py +0 -24
  99. unrealon_driver/src/logging/driver_logger.py +0 -512
  100. unrealon_driver/src/services/__init__.py +0 -24
  101. unrealon_driver/src/services/browser_service.py +0 -726
  102. unrealon_driver/src/services/llm/__init__.py +0 -15
  103. unrealon_driver/src/services/llm/browser_llm_service.py +0 -363
  104. unrealon_driver/src/services/llm/llm.py +0 -195
  105. unrealon_driver/src/services/logger_service.py +0 -232
  106. unrealon_driver/src/services/metrics_service.py +0 -185
  107. unrealon_driver/src/services/scheduler_service.py +0 -489
  108. unrealon_driver/src/services/websocket_service.py +0 -362
  109. unrealon_driver/src/utils/__init__.py +0 -16
  110. unrealon_driver/src/utils/service_factory.py +0 -317
  111. unrealon_driver/src/utils/time_formatter.py +0 -338
  112. unrealon_llm/README.md +0 -44
  113. unrealon_llm/__init__.py +0 -26
  114. unrealon_llm/pyproject.toml +0 -154
  115. unrealon_llm/src/__init__.py +0 -228
  116. unrealon_llm/src/cli/__init__.py +0 -0
  117. unrealon_llm/src/core/__init__.py +0 -11
  118. unrealon_llm/src/core/smart_client.py +0 -438
  119. unrealon_llm/src/dto/__init__.py +0 -155
  120. unrealon_llm/src/dto/models/__init__.py +0 -0
  121. unrealon_llm/src/dto/models/config.py +0 -343
  122. unrealon_llm/src/dto/models/core.py +0 -328
  123. unrealon_llm/src/dto/models/enums.py +0 -123
  124. unrealon_llm/src/dto/models/html_analysis.py +0 -345
  125. unrealon_llm/src/dto/models/statistics.py +0 -473
  126. unrealon_llm/src/dto/models/translation.py +0 -383
  127. unrealon_llm/src/dto/models/type_conversion.py +0 -462
  128. unrealon_llm/src/dto/schemas/__init__.py +0 -0
  129. unrealon_llm/src/exceptions.py +0 -392
  130. unrealon_llm/src/llm_config/__init__.py +0 -20
  131. unrealon_llm/src/llm_config/logging_config.py +0 -178
  132. unrealon_llm/src/llm_logging/__init__.py +0 -42
  133. unrealon_llm/src/llm_logging/llm_events.py +0 -107
  134. unrealon_llm/src/llm_logging/llm_logger.py +0 -466
  135. unrealon_llm/src/managers/__init__.py +0 -15
  136. unrealon_llm/src/managers/cache_manager.py +0 -67
  137. unrealon_llm/src/managers/cost_manager.py +0 -107
  138. unrealon_llm/src/managers/request_manager.py +0 -298
  139. unrealon_llm/src/modules/__init__.py +0 -0
  140. unrealon_llm/src/modules/html_processor/__init__.py +0 -25
  141. unrealon_llm/src/modules/html_processor/base_processor.py +0 -415
  142. unrealon_llm/src/modules/html_processor/details_processor.py +0 -85
  143. unrealon_llm/src/modules/html_processor/listing_processor.py +0 -91
  144. unrealon_llm/src/modules/html_processor/models/__init__.py +0 -20
  145. unrealon_llm/src/modules/html_processor/models/processing_models.py +0 -40
  146. unrealon_llm/src/modules/html_processor/models/universal_model.py +0 -56
  147. unrealon_llm/src/modules/html_processor/processor.py +0 -102
  148. unrealon_llm/src/modules/llm/__init__.py +0 -0
  149. unrealon_llm/src/modules/translator/__init__.py +0 -0
  150. unrealon_llm/src/provider.py +0 -116
  151. unrealon_llm/src/utils/__init__.py +0 -95
  152. unrealon_llm/src/utils/common.py +0 -64
  153. unrealon_llm/src/utils/data_extractor.py +0 -188
  154. unrealon_llm/src/utils/html_cleaner.py +0 -767
  155. unrealon_llm/src/utils/language_detector.py +0 -308
  156. unrealon_llm/src/utils/models_cache.py +0 -592
  157. unrealon_llm/src/utils/smart_counter.py +0 -229
  158. unrealon_llm/src/utils/token_counter.py +0 -189
  159. unrealon_sdk/README.md +0 -25
  160. unrealon_sdk/__init__.py +0 -30
  161. unrealon_sdk/pyproject.toml +0 -231
  162. unrealon_sdk/src/__init__.py +0 -150
  163. unrealon_sdk/src/cli/__init__.py +0 -12
  164. unrealon_sdk/src/cli/commands/__init__.py +0 -22
  165. unrealon_sdk/src/cli/commands/benchmark.py +0 -42
  166. unrealon_sdk/src/cli/commands/diagnostics.py +0 -573
  167. unrealon_sdk/src/cli/commands/health.py +0 -46
  168. unrealon_sdk/src/cli/commands/integration.py +0 -498
  169. unrealon_sdk/src/cli/commands/reports.py +0 -43
  170. unrealon_sdk/src/cli/commands/security.py +0 -36
  171. unrealon_sdk/src/cli/commands/server.py +0 -483
  172. unrealon_sdk/src/cli/commands/servers.py +0 -56
  173. unrealon_sdk/src/cli/commands/tests.py +0 -55
  174. unrealon_sdk/src/cli/main.py +0 -126
  175. unrealon_sdk/src/cli/utils/reporter.py +0 -519
  176. unrealon_sdk/src/clients/openapi.yaml +0 -3347
  177. unrealon_sdk/src/clients/python_http/__init__.py +0 -3
  178. unrealon_sdk/src/clients/python_http/api_config.py +0 -228
  179. unrealon_sdk/src/clients/python_http/models/BaseModel.py +0 -12
  180. unrealon_sdk/src/clients/python_http/models/BroadcastDeliveryStats.py +0 -33
  181. unrealon_sdk/src/clients/python_http/models/BroadcastMessage.py +0 -17
  182. unrealon_sdk/src/clients/python_http/models/BroadcastMessageRequest.py +0 -35
  183. unrealon_sdk/src/clients/python_http/models/BroadcastPriority.py +0 -10
  184. unrealon_sdk/src/clients/python_http/models/BroadcastResponse.py +0 -21
  185. unrealon_sdk/src/clients/python_http/models/BroadcastResultResponse.py +0 -33
  186. unrealon_sdk/src/clients/python_http/models/BroadcastTarget.py +0 -11
  187. unrealon_sdk/src/clients/python_http/models/ConnectionStats.py +0 -27
  188. unrealon_sdk/src/clients/python_http/models/ConnectionsResponse.py +0 -21
  189. unrealon_sdk/src/clients/python_http/models/DeveloperMessageResponse.py +0 -23
  190. unrealon_sdk/src/clients/python_http/models/ErrorResponse.py +0 -25
  191. unrealon_sdk/src/clients/python_http/models/HTTPValidationError.py +0 -16
  192. unrealon_sdk/src/clients/python_http/models/HealthResponse.py +0 -23
  193. unrealon_sdk/src/clients/python_http/models/HealthStatus.py +0 -33
  194. unrealon_sdk/src/clients/python_http/models/LogLevel.py +0 -10
  195. unrealon_sdk/src/clients/python_http/models/LoggingRequest.py +0 -27
  196. unrealon_sdk/src/clients/python_http/models/LoggingResponse.py +0 -23
  197. unrealon_sdk/src/clients/python_http/models/MaintenanceMode.py +0 -9
  198. unrealon_sdk/src/clients/python_http/models/MaintenanceModeRequest.py +0 -33
  199. unrealon_sdk/src/clients/python_http/models/MaintenanceStatusResponse.py +0 -39
  200. unrealon_sdk/src/clients/python_http/models/ParserCommandRequest.py +0 -25
  201. unrealon_sdk/src/clients/python_http/models/ParserMessageResponse.py +0 -21
  202. unrealon_sdk/src/clients/python_http/models/ParserRegistrationRequest.py +0 -28
  203. unrealon_sdk/src/clients/python_http/models/ParserRegistrationResponse.py +0 -25
  204. unrealon_sdk/src/clients/python_http/models/ParserType.py +0 -10
  205. unrealon_sdk/src/clients/python_http/models/ProxyBlockRequest.py +0 -19
  206. unrealon_sdk/src/clients/python_http/models/ProxyEndpointResponse.py +0 -20
  207. unrealon_sdk/src/clients/python_http/models/ProxyListResponse.py +0 -19
  208. unrealon_sdk/src/clients/python_http/models/ProxyProvider.py +0 -10
  209. unrealon_sdk/src/clients/python_http/models/ProxyPurchaseRequest.py +0 -25
  210. unrealon_sdk/src/clients/python_http/models/ProxyResponse.py +0 -47
  211. unrealon_sdk/src/clients/python_http/models/ProxyRotationRequest.py +0 -23
  212. unrealon_sdk/src/clients/python_http/models/ProxyStatus.py +0 -10
  213. unrealon_sdk/src/clients/python_http/models/ProxyUsageRequest.py +0 -19
  214. unrealon_sdk/src/clients/python_http/models/ProxyUsageStatsResponse.py +0 -26
  215. unrealon_sdk/src/clients/python_http/models/ServiceRegistrationDto.py +0 -23
  216. unrealon_sdk/src/clients/python_http/models/ServiceStatsResponse.py +0 -31
  217. unrealon_sdk/src/clients/python_http/models/SessionStartRequest.py +0 -23
  218. unrealon_sdk/src/clients/python_http/models/SuccessResponse.py +0 -25
  219. unrealon_sdk/src/clients/python_http/models/SystemNotificationResponse.py +0 -23
  220. unrealon_sdk/src/clients/python_http/models/ValidationError.py +0 -18
  221. unrealon_sdk/src/clients/python_http/models/ValidationErrorResponse.py +0 -21
  222. unrealon_sdk/src/clients/python_http/models/WebSocketMetrics.py +0 -21
  223. unrealon_sdk/src/clients/python_http/models/__init__.py +0 -44
  224. unrealon_sdk/src/clients/python_http/services/None_service.py +0 -35
  225. unrealon_sdk/src/clients/python_http/services/ParserManagement_service.py +0 -190
  226. unrealon_sdk/src/clients/python_http/services/ProxyManagement_service.py +0 -289
  227. unrealon_sdk/src/clients/python_http/services/SocketLogging_service.py +0 -187
  228. unrealon_sdk/src/clients/python_http/services/SystemHealth_service.py +0 -119
  229. unrealon_sdk/src/clients/python_http/services/WebSocketAPI_service.py +0 -198
  230. unrealon_sdk/src/clients/python_http/services/__init__.py +0 -0
  231. unrealon_sdk/src/clients/python_http/services/admin_service.py +0 -125
  232. unrealon_sdk/src/clients/python_http/services/async_None_service.py +0 -35
  233. unrealon_sdk/src/clients/python_http/services/async_ParserManagement_service.py +0 -190
  234. unrealon_sdk/src/clients/python_http/services/async_ProxyManagement_service.py +0 -289
  235. unrealon_sdk/src/clients/python_http/services/async_SocketLogging_service.py +0 -189
  236. unrealon_sdk/src/clients/python_http/services/async_SystemHealth_service.py +0 -123
  237. unrealon_sdk/src/clients/python_http/services/async_WebSocketAPI_service.py +0 -200
  238. unrealon_sdk/src/clients/python_http/services/async_admin_service.py +0 -125
  239. unrealon_sdk/src/clients/python_websocket/__init__.py +0 -28
  240. unrealon_sdk/src/clients/python_websocket/client.py +0 -490
  241. unrealon_sdk/src/clients/python_websocket/events.py +0 -732
  242. unrealon_sdk/src/clients/python_websocket/example.py +0 -136
  243. unrealon_sdk/src/clients/python_websocket/types.py +0 -871
  244. unrealon_sdk/src/core/__init__.py +0 -64
  245. unrealon_sdk/src/core/client.py +0 -556
  246. unrealon_sdk/src/core/config.py +0 -465
  247. unrealon_sdk/src/core/exceptions.py +0 -239
  248. unrealon_sdk/src/core/metadata.py +0 -191
  249. unrealon_sdk/src/core/models.py +0 -142
  250. unrealon_sdk/src/core/types.py +0 -68
  251. unrealon_sdk/src/dto/__init__.py +0 -268
  252. unrealon_sdk/src/dto/authentication.py +0 -108
  253. unrealon_sdk/src/dto/cache.py +0 -208
  254. unrealon_sdk/src/dto/common.py +0 -19
  255. unrealon_sdk/src/dto/concurrency.py +0 -393
  256. unrealon_sdk/src/dto/events.py +0 -108
  257. unrealon_sdk/src/dto/health.py +0 -339
  258. unrealon_sdk/src/dto/load_balancing.py +0 -336
  259. unrealon_sdk/src/dto/logging.py +0 -230
  260. unrealon_sdk/src/dto/performance.py +0 -165
  261. unrealon_sdk/src/dto/rate_limiting.py +0 -295
  262. unrealon_sdk/src/dto/resource_pooling.py +0 -128
  263. unrealon_sdk/src/dto/structured_logging.py +0 -112
  264. unrealon_sdk/src/dto/task_scheduling.py +0 -121
  265. unrealon_sdk/src/dto/websocket.py +0 -55
  266. unrealon_sdk/src/enterprise/__init__.py +0 -59
  267. unrealon_sdk/src/enterprise/authentication.py +0 -401
  268. unrealon_sdk/src/enterprise/cache_manager.py +0 -578
  269. unrealon_sdk/src/enterprise/error_recovery.py +0 -494
  270. unrealon_sdk/src/enterprise/event_system.py +0 -549
  271. unrealon_sdk/src/enterprise/health_monitor.py +0 -747
  272. unrealon_sdk/src/enterprise/load_balancer.py +0 -964
  273. unrealon_sdk/src/enterprise/logging/__init__.py +0 -68
  274. unrealon_sdk/src/enterprise/logging/cleanup.py +0 -156
  275. unrealon_sdk/src/enterprise/logging/development.py +0 -744
  276. unrealon_sdk/src/enterprise/logging/service.py +0 -410
  277. unrealon_sdk/src/enterprise/multithreading_manager.py +0 -853
  278. unrealon_sdk/src/enterprise/performance_monitor.py +0 -539
  279. unrealon_sdk/src/enterprise/proxy_manager.py +0 -696
  280. unrealon_sdk/src/enterprise/rate_limiter.py +0 -652
  281. unrealon_sdk/src/enterprise/resource_pool.py +0 -763
  282. unrealon_sdk/src/enterprise/task_scheduler.py +0 -709
  283. unrealon_sdk/src/internal/__init__.py +0 -10
  284. unrealon_sdk/src/internal/command_router.py +0 -497
  285. unrealon_sdk/src/internal/connection_manager.py +0 -397
  286. unrealon_sdk/src/internal/http_client.py +0 -446
  287. unrealon_sdk/src/internal/websocket_client.py +0 -420
  288. unrealon_sdk/src/provider.py +0 -471
  289. unrealon_sdk/src/utils.py +0 -234
  290. /unrealon_browser/{src/cli → cli}/__init__.py +0 -0
  291. /unrealon_browser/{src/cli → cli}/interactive_mode.py +0 -0
  292. /unrealon_browser/{src/cli → cli}/main.py +0 -0
  293. /unrealon_browser/{src/core → core}/__init__.py +0 -0
  294. /unrealon_browser/{src/dto → dto}/__init__.py +0 -0
  295. /unrealon_browser/{src/dto → dto}/models/config.py +0 -0
  296. /unrealon_browser/{src/dto → dto}/models/core.py +0 -0
  297. /unrealon_browser/{src/dto → dto}/models/dataclasses.py +0 -0
  298. /unrealon_browser/{src/dto → dto}/models/detection.py +0 -0
  299. /unrealon_browser/{src/dto → dto}/models/enums.py +0 -0
  300. /unrealon_browser/{src/dto → dto}/models/statistics.py +0 -0
  301. /unrealon_browser/{src/managers → managers}/__init__.py +0 -0
  302. /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
- ]