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,709 +0,0 @@
1
- """
2
- Task Scheduler - Layer 4 Concurrency Service
3
-
4
- Advanced task scheduling system with priority-based execution, dependency management,
5
- and intelligent scheduling algorithms. Provides enterprise-grade task orchestration
6
- with automatic retry, timeout handling, and performance optimization.
7
-
8
- Features:
9
- - Priority-based task queuing with multiple priority levels
10
- - Dependency management with cycle detection
11
- - Scheduled execution with cron-like scheduling
12
- - Automatic retry with intelligent backoff strategies
13
- - Timeout handling and resource management
14
- - Progress tracking and result aggregation
15
- - Cancellation support with cleanup
16
- - Performance-based task optimization
17
- - Dead letter queue for failed tasks
18
- - Task result caching and persistence
19
- """
20
-
21
- import asyncio
22
- import logging
23
- import time
24
- import heapq
25
- import threading
26
- from typing import Dict, List, Optional, Any, Callable, Set, Union, Tuple
27
- from datetime import datetime, timezone, timedelta
28
- from collections import defaultdict, deque
29
- from dataclasses import dataclass, field
30
- from enum import Enum
31
- import uuid
32
- import weakref
33
-
34
- # Core SDK components
35
- from unrealon_sdk.src.core.config import AdapterConfig
36
- from unrealon_sdk.src.utils import generate_correlation_id
37
-
38
- # DTO models
39
- from unrealon_sdk.src.dto.logging import SDKEventType, SDKSeverity
40
- from unrealon_sdk.src.dto.concurrency import (
41
- TaskPriority,
42
- TaskStatus,
43
- ConcurrencyEventType,
44
- Task,
45
- ConcurrencyMetrics,
46
- )
47
- from unrealon_sdk.src.dto.task_scheduling import (
48
- ScheduleType,
49
- TaskSchedulerStrategy,
50
- ScheduleInfo,
51
- TaskDependency,
52
- TaskProgress,
53
- TaskSchedulerConfig,
54
- )
55
-
56
- # Development logging
57
- from typing import TYPE_CHECKING
58
-
59
- if TYPE_CHECKING:
60
- from unrealon_sdk.src.enterprise.logging import DevelopmentLogger
61
-
62
- logger = logging.getLogger(__name__)
63
-
64
-
65
- class TaskScheduler:
66
- """
67
- Enterprise-grade task scheduler.
68
-
69
- Provides advanced task scheduling with priority management,
70
- dependency resolution, and comprehensive execution monitoring.
71
- """
72
-
73
- def __init__(
74
- self,
75
- config: AdapterConfig,
76
- scheduler_config: Optional[TaskSchedulerConfig] = None,
77
- dev_logger: Optional["DevelopmentLogger"] = None,
78
- ):
79
- """Initialize task scheduler."""
80
- self.config = config
81
- self.scheduler_config = scheduler_config or TaskSchedulerConfig()
82
- self.dev_logger = dev_logger
83
-
84
- # Task storage
85
- self._tasks: Dict[str, Task] = {}
86
- self._scheduled_tasks: List[Tuple[float, str]] = [] # (execution_time, task_id)
87
- self._running_tasks: Dict[str, asyncio.Task] = {}
88
- self._completed_tasks: Dict[str, Task] = {}
89
- self._failed_tasks: Dict[str, Task] = {}
90
-
91
- # Dependency management
92
- self._dependencies: Dict[str, List[TaskDependency]] = defaultdict(list)
93
- self._waiting_tasks: Dict[str, Set[str]] = defaultdict(set) # task_id -> depends_on_ids
94
- self._dependent_tasks: Dict[str, Set[str]] = defaultdict(set) # task_id -> dependent_ids
95
-
96
- # Scheduling
97
- self._schedule_info: Dict[str, ScheduleInfo] = {}
98
- self._recurring_tasks: Set[str] = set()
99
-
100
- # Progress tracking
101
- self._task_progress: Dict[str, TaskProgress] = {}
102
-
103
- # Dead letter queue
104
- self._dead_letter_queue: deque[Task] = deque(
105
- maxlen=self.scheduler_config.dead_letter_max_size
106
- )
107
-
108
- # Result caching
109
- self._result_cache: Dict[str, Any] = {}
110
- self._cache_timestamps: Dict[str, datetime] = {}
111
-
112
- # Performance metrics
113
- self._metrics = ConcurrencyMetrics()
114
- self._task_performance: Dict[str, List[float]] = defaultdict(list)
115
-
116
- # Background tasks
117
- self._scheduler_task: Optional[asyncio.Task[None]] = None
118
- self._cleanup_task: Optional[asyncio.Task[None]] = None
119
- self._metrics_task: Optional[asyncio.Task[None]] = None
120
- self._shutdown = False
121
-
122
- # Thread safety
123
- self._lock = threading.RLock()
124
-
125
- # Task execution callbacks
126
- self._on_task_start: Optional[Callable[[Task], None]] = None
127
- self._on_task_complete: Optional[Callable[[Task, Any], None]] = None
128
- self._on_task_error: Optional[Callable[[Task, Exception], None]] = None
129
-
130
- self._log_info("Task scheduler initialized")
131
-
132
- async def start(self) -> None:
133
- """Start task scheduler."""
134
- if self._scheduler_task is None:
135
- self._scheduler_task = asyncio.create_task(self._scheduler_loop())
136
-
137
- if self._cleanup_task is None:
138
- self._cleanup_task = asyncio.create_task(self._cleanup_loop())
139
-
140
- if self._metrics_task is None:
141
- self._metrics_task = asyncio.create_task(self._metrics_loop())
142
-
143
- self._log_info("Task scheduler started")
144
-
145
- async def stop(self) -> None:
146
- """Stop task scheduler."""
147
- self._shutdown = True
148
-
149
- # Cancel running tasks
150
- for task_id, task in list(self._running_tasks.items()):
151
- task.cancel()
152
- try:
153
- await task
154
- except asyncio.CancelledError:
155
- pass
156
-
157
- # Cancel background tasks
158
- for task in [self._scheduler_task, self._cleanup_task, self._metrics_task]:
159
- if task:
160
- task.cancel()
161
- try:
162
- await task
163
- except asyncio.CancelledError:
164
- pass
165
-
166
- self._log_info("Task scheduler stopped")
167
-
168
- def schedule_task(
169
- self,
170
- task_func: Callable,
171
- *args,
172
- task_name: Optional[str] = None,
173
- priority: TaskPriority = TaskPriority.NORMAL,
174
- schedule_type: ScheduleType = ScheduleType.IMMEDIATE,
175
- scheduled_time: Optional[datetime] = None,
176
- delay_seconds: Optional[float] = None,
177
- dependencies: Optional[List[str]] = None,
178
- timeout_seconds: Optional[float] = None,
179
- max_retries: Optional[int] = None,
180
- context: Optional[Dict[str, Any]] = None,
181
- **kwargs,
182
- ) -> str:
183
- """Schedule task for execution."""
184
-
185
- # Create task
186
- task = Task(
187
- task_name=task_name or f"{task_func.__name__}",
188
- task_type=f"{task_func.__module__}.{task_func.__name__}",
189
- priority=priority,
190
- dependencies=dependencies or [],
191
- timeout_seconds=timeout_seconds or self.scheduler_config.default_timeout_seconds,
192
- max_retries=max_retries or self.scheduler_config.max_retries,
193
- context=context or {},
194
- )
195
-
196
- # Store function and arguments
197
- task.context.update(
198
- {
199
- "func": task_func,
200
- "args": args,
201
- "kwargs": kwargs,
202
- }
203
- )
204
-
205
- # Create schedule info
206
- schedule_info = ScheduleInfo(schedule_type=schedule_type)
207
-
208
- if schedule_type == ScheduleType.DELAYED and delay_seconds:
209
- schedule_info.delay_seconds = delay_seconds
210
- schedule_info.next_execution = datetime.now(timezone.utc) + timedelta(
211
- seconds=delay_seconds
212
- )
213
- elif schedule_type == ScheduleType.SCHEDULED and scheduled_time:
214
- schedule_info.scheduled_time = scheduled_time
215
- schedule_info.next_execution = scheduled_time
216
- else:
217
- schedule_info.next_execution = datetime.now(timezone.utc)
218
-
219
- with self._lock:
220
- # Store task and schedule info
221
- self._tasks[task.task_id] = task
222
- self._schedule_info[task.task_id] = schedule_info
223
-
224
- # Handle dependencies
225
- if task.dependencies:
226
- self._setup_dependencies(task)
227
-
228
- # Add to schedule if not waiting for dependencies
229
- if not self._waiting_tasks.get(task.task_id):
230
- self._add_to_schedule(task.task_id, schedule_info.next_execution)
231
-
232
- # Initialize progress tracking
233
- self._task_progress[task.task_id] = TaskProgress(task_id=task.task_id)
234
-
235
- self._log_task_event(ConcurrencyEventType.TASK_QUEUED, task)
236
- return task.task_id
237
-
238
- def schedule_recurring_task(
239
- self,
240
- task_func: Callable,
241
- interval: timedelta,
242
- *args,
243
- task_name: Optional[str] = None,
244
- priority: TaskPriority = TaskPriority.NORMAL,
245
- max_executions: Optional[int] = None,
246
- start_time: Optional[datetime] = None,
247
- **kwargs,
248
- ) -> str:
249
- """Schedule recurring task."""
250
-
251
- task_id = self.schedule_task(
252
- task_func,
253
- *args,
254
- task_name=task_name,
255
- priority=priority,
256
- schedule_type=ScheduleType.RECURRING,
257
- scheduled_time=start_time or datetime.now(timezone.utc),
258
- **kwargs,
259
- )
260
-
261
- # Update schedule info for recurring
262
- schedule_info = self._schedule_info[task_id]
263
- schedule_info.repeat_interval = interval
264
- schedule_info.max_executions = max_executions
265
-
266
- self._recurring_tasks.add(task_id)
267
- return task_id
268
-
269
- def _setup_dependencies(self, task: Task) -> None:
270
- """Setup task dependencies."""
271
- for dep_id in task.dependencies:
272
- dependency = TaskDependency(
273
- task_id=task.task_id,
274
- depends_on=dep_id,
275
- )
276
- self._dependencies[task.task_id].append(dependency)
277
- self._waiting_tasks[task.task_id].add(dep_id)
278
- self._dependent_tasks[dep_id].add(task.task_id)
279
-
280
- def _add_to_schedule(self, task_id: str, execution_time: datetime) -> None:
281
- """Add task to schedule."""
282
- timestamp = execution_time.timestamp()
283
- heapq.heappush(self._scheduled_tasks, (timestamp, task_id))
284
-
285
- async def _scheduler_loop(self) -> None:
286
- """Main scheduler loop."""
287
- while not self._shutdown:
288
- try:
289
- current_time = time.time()
290
- tasks_to_execute = []
291
-
292
- # Find tasks ready for execution
293
- with self._lock:
294
- while self._scheduled_tasks and self._scheduled_tasks[0][0] <= current_time:
295
- _, task_id = heapq.heappop(self._scheduled_tasks)
296
- if task_id in self._tasks:
297
- tasks_to_execute.append(task_id)
298
-
299
- # Execute ready tasks
300
- for task_id in tasks_to_execute:
301
- if len(self._running_tasks) < self.scheduler_config.max_concurrent_tasks:
302
- await self._execute_task(task_id)
303
- else:
304
- # Re-schedule for later if at capacity
305
- execution_time = datetime.fromtimestamp(current_time + 1, tz=timezone.utc)
306
- self._add_to_schedule(task_id, execution_time)
307
-
308
- # Sleep based on resolution
309
- await asyncio.sleep(self.scheduler_config.schedule_resolution_seconds)
310
-
311
- except asyncio.CancelledError:
312
- break
313
- except Exception as e:
314
- logger.error(f"Error in scheduler loop: {e}")
315
- await asyncio.sleep(1)
316
-
317
- async def _execute_task(self, task_id: str) -> None:
318
- """Execute task."""
319
- if task_id not in self._tasks:
320
- return
321
-
322
- task = self._tasks[task_id]
323
-
324
- # Update task status
325
- task.status = TaskStatus.RUNNING
326
- task.started_at = datetime.now(timezone.utc)
327
-
328
- # Update progress
329
- progress = self._task_progress.get(task_id)
330
- if progress:
331
- progress.started_at = task.started_at
332
- progress.status_message = "Executing..."
333
-
334
- # Create execution task
335
- execution_task = asyncio.create_task(self._run_task_with_timeout(task))
336
- self._running_tasks[task_id] = execution_task
337
-
338
- self._log_task_event(ConcurrencyEventType.TASK_STARTED, task)
339
-
340
- # Call start callback
341
- if self._on_task_start:
342
- try:
343
- self._on_task_start(task)
344
- except Exception as e:
345
- logger.error(f"Error in task start callback: {e}")
346
-
347
- async def _run_task_with_timeout(self, task: Task) -> None:
348
- """Run task with timeout handling."""
349
- try:
350
- # Extract function and arguments
351
- func = task.context["func"]
352
- args = task.context.get("args", ())
353
- kwargs = task.context.get("kwargs", {})
354
-
355
- # Execute with timeout
356
- if task.timeout_seconds:
357
- result = await asyncio.wait_for(
358
- self._execute_task_function(func, args, kwargs), timeout=task.timeout_seconds
359
- )
360
- else:
361
- result = await self._execute_task_function(func, args, kwargs)
362
-
363
- # Task completed successfully
364
- await self._handle_task_completion(task, result)
365
-
366
- except asyncio.TimeoutError:
367
- task.status = TaskStatus.TIMEOUT
368
- task.error_message = f"Task timed out after {task.timeout_seconds} seconds"
369
- await self._handle_task_failure(task, asyncio.TimeoutError("Task timeout"))
370
-
371
- except Exception as e:
372
- task.status = TaskStatus.FAILED
373
- task.error_message = str(e)
374
- await self._handle_task_failure(task, e)
375
-
376
- finally:
377
- # Clean up
378
- self._running_tasks.pop(task.task_id, None)
379
- task.completed_at = datetime.now(timezone.utc)
380
-
381
- if task.started_at:
382
- duration = (task.completed_at - task.started_at).total_seconds() * 1000
383
- task.actual_duration_ms = duration
384
-
385
- # Track performance
386
- task_type = task.task_type
387
- self._task_performance[task_type].append(duration)
388
-
389
- # Keep only recent performance data
390
- if len(self._task_performance[task_type]) > 100:
391
- self._task_performance[task_type] = self._task_performance[task_type][-50:]
392
-
393
- async def _execute_task_function(self, func: Callable, args: tuple, kwargs: dict) -> Any:
394
- """Execute task function (async or sync)."""
395
- if asyncio.iscoroutinefunction(func):
396
- return await func(*args, **kwargs)
397
- else:
398
- # Run sync function in thread pool
399
- loop = asyncio.get_event_loop()
400
- return await loop.run_in_executor(None, lambda: func(*args, **kwargs))
401
-
402
- async def _handle_task_completion(self, task: Task, result: Any) -> None:
403
- """Handle successful task completion."""
404
- task.status = TaskStatus.COMPLETED
405
- task.result = result
406
-
407
- # Update progress
408
- progress = self._task_progress.get(task.task_id)
409
- if progress:
410
- progress.progress_percent = 100.0
411
- progress.status_message = "Completed"
412
- progress.last_update = datetime.now(timezone.utc)
413
-
414
- # Cache result if enabled
415
- if self.scheduler_config.enable_result_caching:
416
- cache_key = f"{task.task_type}:{hash(str(task.context))}"
417
- self._result_cache[cache_key] = result
418
- self._cache_timestamps[cache_key] = datetime.now(timezone.utc)
419
-
420
- # Move to completed tasks
421
- with self._lock:
422
- self._completed_tasks[task.task_id] = task
423
-
424
- # Handle dependent tasks
425
- for dependent_id in self._dependent_tasks.get(task.task_id, set()):
426
- if dependent_id in self._waiting_tasks:
427
- self._waiting_tasks[dependent_id].discard(task.task_id)
428
-
429
- # If all dependencies met, schedule for execution
430
- if not self._waiting_tasks[dependent_id]:
431
- del self._waiting_tasks[dependent_id]
432
- dependent_task = self._tasks.get(dependent_id)
433
- if dependent_task:
434
- schedule_info = self._schedule_info.get(dependent_id)
435
- if schedule_info:
436
- self._add_to_schedule(dependent_id, schedule_info.next_execution)
437
-
438
- # Handle recurring tasks
439
- if task.task_id in self._recurring_tasks:
440
- await self._reschedule_recurring_task(task.task_id)
441
-
442
- self._log_task_event(ConcurrencyEventType.TASK_COMPLETED, task)
443
-
444
- # Call completion callback
445
- if self._on_task_complete:
446
- try:
447
- self._on_task_complete(task, result)
448
- except Exception as e:
449
- logger.error(f"Error in task completion callback: {e}")
450
-
451
- async def _handle_task_failure(self, task: Task, exception: Exception) -> None:
452
- """Handle task failure."""
453
-
454
- # Check if retry is possible
455
- if task.retry_count < task.max_retries:
456
- task.retry_count += 1
457
- task.status = TaskStatus.RETRYING
458
-
459
- # Calculate retry delay with exponential backoff
460
- delay = self.scheduler_config.retry_backoff_factor ** (task.retry_count - 1)
461
- retry_time = datetime.now(timezone.utc) + timedelta(seconds=delay)
462
-
463
- # Re-schedule task
464
- self._add_to_schedule(task.task_id, retry_time)
465
-
466
- self._log_info(
467
- f"Retrying task {task.task_id} (attempt {task.retry_count}/{task.max_retries}) in {delay}s"
468
- )
469
- return
470
-
471
- # Task permanently failed
472
- with self._lock:
473
- self._failed_tasks[task.task_id] = task
474
-
475
- # Add to dead letter queue if enabled
476
- if self.scheduler_config.enable_dead_letter_queue:
477
- self._dead_letter_queue.append(task)
478
-
479
- self._log_task_event(ConcurrencyEventType.TASK_FAILED, task)
480
-
481
- # Call error callback
482
- if self._on_task_error:
483
- try:
484
- self._on_task_error(task, exception)
485
- except Exception as e:
486
- logger.error(f"Error in task error callback: {e}")
487
-
488
- async def _reschedule_recurring_task(self, task_id: str) -> None:
489
- """Reschedule recurring task for next execution."""
490
- schedule_info = self._schedule_info.get(task_id)
491
- if not schedule_info or not schedule_info.repeat_interval:
492
- return
493
-
494
- # Check execution count limit
495
- schedule_info.execution_count += 1
496
- if (
497
- schedule_info.max_executions
498
- and schedule_info.execution_count >= schedule_info.max_executions
499
- ):
500
- self._recurring_tasks.discard(task_id)
501
- return
502
-
503
- # Calculate next execution time
504
- schedule_info.last_execution = datetime.now(timezone.utc)
505
- schedule_info.next_execution = schedule_info.last_execution + schedule_info.repeat_interval
506
-
507
- # Create new task instance for next execution
508
- original_task = self._tasks[task_id]
509
- new_task = Task(
510
- task_name=original_task.task_name,
511
- task_type=original_task.task_type,
512
- priority=original_task.priority,
513
- timeout_seconds=original_task.timeout_seconds,
514
- max_retries=original_task.max_retries,
515
- context=original_task.context.copy(),
516
- )
517
-
518
- # Store new task
519
- self._tasks[new_task.task_id] = new_task
520
- self._schedule_info[new_task.task_id] = schedule_info
521
- self._task_progress[new_task.task_id] = TaskProgress(task_id=new_task.task_id)
522
-
523
- # Schedule for next execution
524
- self._add_to_schedule(new_task.task_id, schedule_info.next_execution)
525
-
526
- async def _cleanup_loop(self) -> None:
527
- """Background cleanup loop."""
528
- while not self._shutdown:
529
- try:
530
- await asyncio.sleep(300) # Cleanup every 5 minutes
531
- await self._cleanup_old_tasks()
532
- await self._cleanup_cache()
533
- except asyncio.CancelledError:
534
- break
535
- except Exception as e:
536
- logger.error(f"Error in cleanup loop: {e}")
537
-
538
- async def _cleanup_old_tasks(self) -> None:
539
- """Clean up old completed/failed tasks."""
540
- cutoff_time = datetime.now(timezone.utc) - timedelta(hours=24)
541
-
542
- with self._lock:
543
- # Clean up completed tasks
544
- old_completed = [
545
- task_id
546
- for task_id, task in self._completed_tasks.items()
547
- if task.completed_at and task.completed_at < cutoff_time
548
- ]
549
- for task_id in old_completed:
550
- del self._completed_tasks[task_id]
551
- self._task_progress.pop(task_id, None)
552
-
553
- # Clean up failed tasks
554
- old_failed = [
555
- task_id
556
- for task_id, task in self._failed_tasks.items()
557
- if task.completed_at and task.completed_at < cutoff_time
558
- ]
559
- for task_id in old_failed:
560
- del self._failed_tasks[task_id]
561
- self._task_progress.pop(task_id, None)
562
-
563
- if old_completed or old_failed:
564
- self._log_info(
565
- f"Cleaned up {len(old_completed)} completed and {len(old_failed)} failed tasks"
566
- )
567
-
568
- async def _cleanup_cache(self) -> None:
569
- """Clean up expired cache entries."""
570
- if not self.scheduler_config.enable_result_caching:
571
- return
572
-
573
- cutoff_time = datetime.now(timezone.utc) - timedelta(
574
- seconds=self.scheduler_config.cache_ttl_seconds
575
- )
576
-
577
- expired_keys = [
578
- key for key, timestamp in self._cache_timestamps.items() if timestamp < cutoff_time
579
- ]
580
-
581
- for key in expired_keys:
582
- self._result_cache.pop(key, None)
583
- self._cache_timestamps.pop(key, None)
584
-
585
- if expired_keys:
586
- self._log_info(f"Cleaned up {len(expired_keys)} expired cache entries")
587
-
588
- async def _metrics_loop(self) -> None:
589
- """Background metrics collection loop."""
590
- while not self._shutdown:
591
- try:
592
- await asyncio.sleep(60) # Collect every minute
593
- await self._collect_metrics()
594
- except asyncio.CancelledError:
595
- break
596
- except Exception as e:
597
- logger.error(f"Error in metrics loop: {e}")
598
-
599
- async def _collect_metrics(self) -> None:
600
- """Collect scheduler metrics."""
601
- with self._lock:
602
- self._metrics.total_tasks = len(self._tasks)
603
- self._metrics.running_tasks = len(self._running_tasks)
604
- self._metrics.pending_tasks = len(self._scheduled_tasks)
605
- self._metrics.completed_tasks = len(self._completed_tasks)
606
- self._metrics.failed_tasks = len(self._failed_tasks)
607
-
608
- # Calculate average task duration
609
- all_durations = []
610
- for durations in self._task_performance.values():
611
- all_durations.extend(durations)
612
-
613
- if all_durations:
614
- self._metrics.avg_task_duration_ms = sum(all_durations) / len(all_durations)
615
-
616
- def cancel_task(self, task_id: str) -> bool:
617
- """Cancel task execution."""
618
- with self._lock:
619
- # Cancel if running
620
- if task_id in self._running_tasks:
621
- execution_task = self._running_tasks[task_id]
622
- execution_task.cancel()
623
-
624
- # Update task status
625
- if task_id in self._tasks:
626
- self._tasks[task_id].status = TaskStatus.CANCELLED
627
-
628
- return True
629
-
630
- # Remove from schedule if pending
631
- elif task_id in self._tasks:
632
- self._tasks[task_id].status = TaskStatus.CANCELLED
633
-
634
- # Remove from scheduled tasks
635
- self._scheduled_tasks = [
636
- (timestamp, tid) for timestamp, tid in self._scheduled_tasks if tid != task_id
637
- ]
638
- heapq.heapify(self._scheduled_tasks)
639
-
640
- return True
641
-
642
- return False
643
-
644
- def get_task_status(self, task_id: str) -> Optional[Task]:
645
- """Get task status."""
646
- return (
647
- self._tasks.get(task_id)
648
- or self._completed_tasks.get(task_id)
649
- or self._failed_tasks.get(task_id)
650
- )
651
-
652
- def get_task_progress(self, task_id: str) -> Optional[TaskProgress]:
653
- """Get task progress."""
654
- return self._task_progress.get(task_id)
655
-
656
- def get_metrics(self) -> ConcurrencyMetrics:
657
- """Get scheduler metrics."""
658
- return self._metrics.model_copy()
659
-
660
- def get_dead_letter_queue(self) -> List[Task]:
661
- """Get dead letter queue contents."""
662
- return list(self._dead_letter_queue)
663
-
664
- def set_callbacks(
665
- self,
666
- on_start: Optional[Callable[[Task], None]] = None,
667
- on_complete: Optional[Callable[[Task, Any], None]] = None,
668
- on_error: Optional[Callable[[Task, Exception], None]] = None,
669
- ) -> None:
670
- """Set task execution callbacks."""
671
- self._on_task_start = on_start
672
- self._on_task_complete = on_complete
673
- self._on_task_error = on_error
674
-
675
- def _log_task_event(self, event_type: ConcurrencyEventType, task: Task) -> None:
676
- """Log task event."""
677
- message = f"Task {event_type.value}: {task.task_name} ({task.task_id})"
678
-
679
- if self.dev_logger:
680
- self.dev_logger.log_debug(
681
- SDKEventType.DEBUG_CHECKPOINT,
682
- message,
683
- details={
684
- "event_type": event_type.value,
685
- "task_id": task.task_id,
686
- "task_status": task.status.value,
687
- "priority": task.priority.value,
688
- },
689
- )
690
- else:
691
- logger.debug(message)
692
-
693
- def _log_info(self, message: str, **kwargs: Any) -> None:
694
- """Log info message."""
695
- if self.dev_logger:
696
- self.dev_logger.log_info(
697
- SDKEventType.PERFORMANCE_OPTIMIZATION_APPLIED, message, **kwargs
698
- )
699
- else:
700
- logger.info(message)
701
-
702
-
703
- __all__ = [
704
- # Main business logic class
705
- "TaskScheduler",
706
- # Note: Task scheduling models are available via DTO imports:
707
- # from unrealon_sdk.src.dto.task_scheduling import ...
708
- # from unrealon_sdk.src.dto.concurrency import ...
709
- ]