kailash 0.9.15__py3-none-any.whl → 0.9.17__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 (33) hide show
  1. kailash/__init__.py +4 -3
  2. kailash/middleware/database/base_models.py +7 -1
  3. kailash/migration/__init__.py +30 -0
  4. kailash/migration/cli.py +340 -0
  5. kailash/migration/compatibility_checker.py +662 -0
  6. kailash/migration/configuration_validator.py +837 -0
  7. kailash/migration/documentation_generator.py +1828 -0
  8. kailash/migration/examples/__init__.py +5 -0
  9. kailash/migration/examples/complete_migration_example.py +692 -0
  10. kailash/migration/migration_assistant.py +715 -0
  11. kailash/migration/performance_comparator.py +760 -0
  12. kailash/migration/regression_detector.py +1141 -0
  13. kailash/migration/tests/__init__.py +6 -0
  14. kailash/migration/tests/test_compatibility_checker.py +403 -0
  15. kailash/migration/tests/test_integration.py +463 -0
  16. kailash/migration/tests/test_migration_assistant.py +397 -0
  17. kailash/migration/tests/test_performance_comparator.py +433 -0
  18. kailash/monitoring/__init__.py +29 -2
  19. kailash/monitoring/asyncsql_metrics.py +275 -0
  20. kailash/nodes/data/async_sql.py +1828 -33
  21. kailash/runtime/local.py +1255 -8
  22. kailash/runtime/monitoring/__init__.py +1 -0
  23. kailash/runtime/monitoring/runtime_monitor.py +780 -0
  24. kailash/runtime/resource_manager.py +3033 -0
  25. kailash/sdk_exceptions.py +21 -0
  26. kailash/workflow/cyclic_runner.py +18 -2
  27. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/METADATA +1 -1
  28. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/RECORD +33 -14
  29. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/WHEEL +0 -0
  30. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/entry_points.txt +0 -0
  31. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/licenses/LICENSE +0 -0
  32. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/licenses/NOTICE +0 -0
  33. {kailash-0.9.15.dist-info → kailash-0.9.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,275 @@
1
+ """
2
+ Prometheus metrics integration for AsyncSQL lock contention monitoring.
3
+
4
+ This module provides easy-to-use Prometheus metrics for monitoring AsyncSQL
5
+ per-pool locking performance and contention patterns.
6
+ """
7
+
8
+ import time
9
+ from typing import Optional, Dict, Any
10
+ from contextlib import asynccontextmanager
11
+
12
+ try:
13
+ import prometheus_client
14
+ PROMETHEUS_AVAILABLE = True
15
+ except ImportError:
16
+ PROMETHEUS_AVAILABLE = False
17
+
18
+
19
+ class AsyncSQLMetrics:
20
+ """Prometheus metrics collector for AsyncSQL lock contention monitoring."""
21
+
22
+ def __init__(self, enabled: bool = True, registry: Optional[prometheus_client.CollectorRegistry] = None):
23
+ """
24
+ Initialize AsyncSQL metrics collector.
25
+
26
+ Args:
27
+ enabled: Whether to collect metrics (disabled if prometheus_client not available)
28
+ registry: Custom Prometheus registry (uses default if None)
29
+ """
30
+ self.enabled = enabled and PROMETHEUS_AVAILABLE
31
+ self.registry = registry or prometheus_client.REGISTRY
32
+
33
+ if not self.enabled:
34
+ return
35
+
36
+ # Lock acquisition counter
37
+ self.lock_acquisition_counter = prometheus_client.Counter(
38
+ 'asyncsql_lock_acquisitions_total',
39
+ 'Total number of AsyncSQL lock acquisitions',
40
+ ['pool_key', 'status'], # status: success, timeout, error
41
+ registry=self.registry
42
+ )
43
+
44
+ # Lock wait time histogram
45
+ self.lock_wait_time_histogram = prometheus_client.Histogram(
46
+ 'asyncsql_lock_wait_seconds',
47
+ 'Time spent waiting for AsyncSQL locks',
48
+ ['pool_key'],
49
+ buckets=(0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, float('inf')),
50
+ registry=self.registry
51
+ )
52
+
53
+ # Active locks gauge
54
+ self.active_locks_gauge = prometheus_client.Gauge(
55
+ 'asyncsql_active_locks',
56
+ 'Number of currently active AsyncSQL locks',
57
+ ['pool_key'],
58
+ registry=self.registry
59
+ )
60
+
61
+ # Pool operations counter
62
+ self.pool_operations_counter = prometheus_client.Counter(
63
+ 'asyncsql_pool_operations_total',
64
+ 'Total number of AsyncSQL pool operations',
65
+ ['pool_key', 'operation'], # operation: create, cleanup, acquire, release
66
+ registry=self.registry
67
+ )
68
+
69
+ # Lock contention summary
70
+ self.lock_contention_summary = prometheus_client.Summary(
71
+ 'asyncsql_lock_contention_seconds',
72
+ 'Summary of AsyncSQL lock contention patterns',
73
+ ['pool_key'],
74
+ registry=self.registry
75
+ )
76
+
77
+ def record_lock_acquisition(self, pool_key: str, status: str, wait_time: float = 0.0):
78
+ """
79
+ Record a lock acquisition event.
80
+
81
+ Args:
82
+ pool_key: The pool key for the lock
83
+ status: 'success', 'timeout', or 'error'
84
+ wait_time: Time spent waiting for the lock in seconds
85
+ """
86
+ if not self.enabled:
87
+ return
88
+
89
+ self.lock_acquisition_counter.labels(pool_key=pool_key, status=status).inc()
90
+
91
+ if wait_time > 0:
92
+ self.lock_wait_time_histogram.labels(pool_key=pool_key).observe(wait_time)
93
+ self.lock_contention_summary.labels(pool_key=pool_key).observe(wait_time)
94
+
95
+ def set_active_locks(self, pool_key: str, count: int):
96
+ """
97
+ Update the count of active locks for a pool.
98
+
99
+ Args:
100
+ pool_key: The pool key
101
+ count: Number of active locks
102
+ """
103
+ if not self.enabled:
104
+ return
105
+
106
+ self.active_locks_gauge.labels(pool_key=pool_key).set(count)
107
+
108
+ def record_pool_operation(self, pool_key: str, operation: str):
109
+ """
110
+ Record a pool operation event.
111
+
112
+ Args:
113
+ pool_key: The pool key
114
+ operation: 'create', 'cleanup', 'acquire', 'release'
115
+ """
116
+ if not self.enabled:
117
+ return
118
+
119
+ self.pool_operations_counter.labels(pool_key=pool_key, operation=operation).inc()
120
+
121
+ @asynccontextmanager
122
+ async def timed_lock_acquisition(self, pool_key: str):
123
+ """
124
+ Context manager to time lock acquisition and automatically record metrics.
125
+
126
+ Usage:
127
+ async with metrics.timed_lock_acquisition('my_pool_key'):
128
+ # Lock acquisition logic here
129
+ async with some_lock:
130
+ # Work while holding lock
131
+ pass
132
+ """
133
+ start_time = time.time()
134
+ status = 'error'
135
+
136
+ try:
137
+ yield
138
+ status = 'success'
139
+ except Exception as e:
140
+ if 'timeout' in str(e).lower():
141
+ status = 'timeout'
142
+ else:
143
+ status = 'error'
144
+ raise
145
+ finally:
146
+ wait_time = time.time() - start_time
147
+ self.record_lock_acquisition(pool_key, status, wait_time)
148
+
149
+
150
+ # Global metrics instance (can be overridden)
151
+ _global_metrics: Optional[AsyncSQLMetrics] = None
152
+
153
+
154
+ def get_global_metrics() -> Optional[AsyncSQLMetrics]:
155
+ """Get the global AsyncSQL metrics instance."""
156
+ global _global_metrics
157
+ if _global_metrics is None and PROMETHEUS_AVAILABLE:
158
+ _global_metrics = AsyncSQLMetrics()
159
+ return _global_metrics
160
+
161
+
162
+ def set_global_metrics(metrics: Optional[AsyncSQLMetrics]):
163
+ """Set the global AsyncSQL metrics instance."""
164
+ global _global_metrics
165
+ _global_metrics = metrics
166
+
167
+
168
+ def enable_metrics(registry: Optional[prometheus_client.CollectorRegistry] = None) -> AsyncSQLMetrics:
169
+ """
170
+ Enable global AsyncSQL metrics collection.
171
+
172
+ Args:
173
+ registry: Custom Prometheus registry (uses default if None)
174
+
175
+ Returns:
176
+ The configured metrics instance
177
+ """
178
+ metrics = AsyncSQLMetrics(enabled=True, registry=registry)
179
+ set_global_metrics(metrics)
180
+ return metrics
181
+
182
+
183
+ def disable_metrics():
184
+ """Disable global AsyncSQL metrics collection."""
185
+ set_global_metrics(None)
186
+
187
+
188
+ # Convenience functions for manual metric recording
189
+ def record_lock_acquisition(pool_key: str, status: str, wait_time: float = 0.0):
190
+ """Record a lock acquisition event using global metrics."""
191
+ metrics = get_global_metrics()
192
+ if metrics:
193
+ metrics.record_lock_acquisition(pool_key, status, wait_time)
194
+
195
+
196
+ def record_pool_operation(pool_key: str, operation: str):
197
+ """Record a pool operation event using global metrics."""
198
+ metrics = get_global_metrics()
199
+ if metrics:
200
+ metrics.record_pool_operation(pool_key, operation)
201
+
202
+
203
+ def set_active_locks(pool_key: str, count: int):
204
+ """Update active locks count using global metrics."""
205
+ metrics = get_global_metrics()
206
+ if metrics:
207
+ metrics.set_active_locks(pool_key, count)
208
+
209
+
210
+ # Integration example for AsyncSQLDatabaseNode
211
+ def integrate_with_async_sql():
212
+ """
213
+ Example of how to integrate metrics with AsyncSQLDatabaseNode.
214
+
215
+ This would typically be called during AsyncSQL initialization or
216
+ through a configuration setting.
217
+ """
218
+ if not PROMETHEUS_AVAILABLE:
219
+ return None
220
+
221
+ # Enable metrics
222
+ metrics = enable_metrics()
223
+
224
+ # Example: monkey-patch AsyncSQL methods to include metrics
225
+ # (This is just an example - actual integration would be cleaner)
226
+ from kailash.nodes.data.async_sql import AsyncSQLDatabaseNode
227
+
228
+ # Store original methods
229
+ original_get_pool_creation_lock = AsyncSQLDatabaseNode._get_pool_creation_lock
230
+ original_acquire_lock = AsyncSQLDatabaseNode._acquire_pool_lock_with_timeout
231
+
232
+ @classmethod
233
+ def instrumented_get_pool_creation_lock(cls, pool_key: str):
234
+ """Instrumented version that records pool operations."""
235
+ record_pool_operation(pool_key, 'acquire')
236
+ return original_get_pool_creation_lock(pool_key)
237
+
238
+ @classmethod
239
+ async def instrumented_acquire_lock(cls, pool_key: str, timeout: float = 5.0):
240
+ """Instrumented version that records lock acquisitions."""
241
+ async with metrics.timed_lock_acquisition(pool_key):
242
+ async with original_acquire_lock(pool_key, timeout):
243
+ yield
244
+
245
+ # Apply instrumentation
246
+ AsyncSQLDatabaseNode._get_pool_creation_lock = instrumented_get_pool_creation_lock
247
+ AsyncSQLDatabaseNode._acquire_pool_lock_with_timeout = instrumented_acquire_lock
248
+
249
+ return metrics
250
+
251
+
252
+ if __name__ == "__main__":
253
+ # Example usage
254
+ print("AsyncSQL Metrics Module")
255
+ print(f"Prometheus available: {PROMETHEUS_AVAILABLE}")
256
+
257
+ if PROMETHEUS_AVAILABLE:
258
+ # Enable metrics
259
+ metrics = enable_metrics()
260
+
261
+ # Simulate some metrics
262
+ metrics.record_lock_acquisition('test_pool_1', 'success', 0.005)
263
+ metrics.record_lock_acquisition('test_pool_1', 'success', 0.003)
264
+ metrics.record_lock_acquisition('test_pool_2', 'timeout', 5.0)
265
+ metrics.set_active_locks('test_pool_1', 2)
266
+ metrics.record_pool_operation('test_pool_1', 'create')
267
+
268
+ print("Metrics recorded successfully")
269
+ print("Access metrics at: http://localhost:8000/metrics")
270
+ print("(Start prometheus_client HTTP server to view metrics)")
271
+
272
+ # Start metrics server (for testing)
273
+ # prometheus_client.start_http_server(8000)
274
+ else:
275
+ print("Install prometheus_client to enable metrics: pip install prometheus_client")