dory-processor-sdk 0.0.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.
Files changed (86) hide show
  1. dory/__init__.py +101 -0
  2. dory/auth/__init__.py +10 -0
  3. dory/auth/oauth2.py +153 -0
  4. dory/auto_instrument.py +142 -0
  5. dory/cli/__init__.py +5 -0
  6. dory/cli/main.py +137 -0
  7. dory/cli/templates.py +123 -0
  8. dory/config/__init__.py +23 -0
  9. dory/config/defaults.py +24 -0
  10. dory/config/loader.py +430 -0
  11. dory/config/presets.py +73 -0
  12. dory/config/schema.py +84 -0
  13. dory/core/__init__.py +27 -0
  14. dory/core/app.py +434 -0
  15. dory/core/context.py +209 -0
  16. dory/core/lifecycle.py +214 -0
  17. dory/core/meta.py +121 -0
  18. dory/core/modes.py +479 -0
  19. dory/core/processor.py +564 -0
  20. dory/core/signals.py +122 -0
  21. dory/decorators.py +142 -0
  22. dory/edge/__init__.py +88 -0
  23. dory/edge/adaptive.py +644 -0
  24. dory/edge/detector.py +546 -0
  25. dory/edge/fencing.py +488 -0
  26. dory/edge/heartbeat.py +598 -0
  27. dory/edge/role.py +419 -0
  28. dory/errors/__init__.py +139 -0
  29. dory/errors/classification.py +362 -0
  30. dory/errors/codes.py +498 -0
  31. dory/geo/__init__.py +40 -0
  32. dory/geo/geolocalizer.py +1034 -0
  33. dory/health/__init__.py +12 -0
  34. dory/health/probes.py +210 -0
  35. dory/health/server.py +635 -0
  36. dory/k8s/__init__.py +80 -0
  37. dory/k8s/annotation_watcher.py +184 -0
  38. dory/k8s/client.py +251 -0
  39. dory/k8s/labels.py +505 -0
  40. dory/k8s/pod_metadata.py +182 -0
  41. dory/logging/__init__.py +9 -0
  42. dory/logging/logger.py +148 -0
  43. dory/metrics/__init__.py +7 -0
  44. dory/metrics/collector.py +301 -0
  45. dory/middleware/__init__.py +46 -0
  46. dory/middleware/connection_tracker.py +608 -0
  47. dory/middleware/request_id.py +325 -0
  48. dory/middleware/request_tracker.py +511 -0
  49. dory/migration/__init__.py +33 -0
  50. dory/migration/configmap.py +232 -0
  51. dory/migration/s3_store.py +594 -0
  52. dory/migration/serialization.py +135 -0
  53. dory/migration/state_manager.py +286 -0
  54. dory/migration/transfer.py +382 -0
  55. dory/monitoring/__init__.py +29 -0
  56. dory/monitoring/opentelemetry.py +489 -0
  57. dory/output/__init__.py +31 -0
  58. dory/output/envelope.py +137 -0
  59. dory/output/formatter.py +113 -0
  60. dory/output/rabbitmq.py +632 -0
  61. dory/output/routing.py +318 -0
  62. dory/output/validator.py +199 -0
  63. dory/py.typed +2 -0
  64. dory/recovery/__init__.py +60 -0
  65. dory/recovery/golden_image.py +487 -0
  66. dory/recovery/golden_snapshot.py +713 -0
  67. dory/recovery/golden_validator.py +518 -0
  68. dory/recovery/partial_recovery.py +482 -0
  69. dory/recovery/recovery_decision.py +242 -0
  70. dory/recovery/restart_detector.py +142 -0
  71. dory/recovery/state_validator.py +183 -0
  72. dory/resilience/__init__.py +45 -0
  73. dory/resilience/circuit_breaker.py +457 -0
  74. dory/resilience/retry.py +389 -0
  75. dory/simple.py +342 -0
  76. dory/types.py +68 -0
  77. dory/utils/__init__.py +31 -0
  78. dory/utils/errors.py +59 -0
  79. dory/utils/retry.py +115 -0
  80. dory/utils/timeout.py +80 -0
  81. dory_processor_sdk-0.0.1.dist-info/METADATA +424 -0
  82. dory_processor_sdk-0.0.1.dist-info/RECORD +86 -0
  83. dory_processor_sdk-0.0.1.dist-info/WHEEL +5 -0
  84. dory_processor_sdk-0.0.1.dist-info/entry_points.txt +2 -0
  85. dory_processor_sdk-0.0.1.dist-info/licenses/LICENSE +201 -0
  86. dory_processor_sdk-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,12 @@
1
+ """Health check and metrics HTTP server."""
2
+
3
+ from dory.health.server import HealthServer
4
+ from dory.health.probes import LivenessProbe, ReadinessProbe, ProbeResult, StartupProbe
5
+
6
+ __all__ = [
7
+ "HealthServer",
8
+ "LivenessProbe",
9
+ "ReadinessProbe",
10
+ "ProbeResult",
11
+ "StartupProbe",
12
+ ]
dory/health/probes.py ADDED
@@ -0,0 +1,210 @@
1
+ """
2
+ Health probe implementations.
3
+
4
+ Provides liveness and readiness probes for Kubernetes.
5
+ """
6
+
7
+ import asyncio
8
+ import inspect
9
+ import logging
10
+ from abc import ABC, abstractmethod
11
+ from dataclasses import dataclass, field
12
+ from typing import Callable, Awaitable, Union
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ @dataclass
18
+ class ProbeResult:
19
+ """Result of a health probe check."""
20
+ healthy: bool
21
+ message: str = ""
22
+ details: dict = field(default_factory=dict)
23
+
24
+ def to_dict(self) -> dict:
25
+ """Convert to dictionary for JSON response."""
26
+ return {
27
+ "healthy": self.healthy,
28
+ "message": self.message,
29
+ "details": self.details,
30
+ }
31
+
32
+
33
+ class HealthProbe(ABC):
34
+ """Abstract base class for health probes."""
35
+
36
+ @abstractmethod
37
+ async def check(self) -> ProbeResult:
38
+ """
39
+ Perform health check.
40
+
41
+ Returns:
42
+ ProbeResult indicating health status
43
+ """
44
+ pass
45
+
46
+
47
+ class LivenessProbe(HealthProbe):
48
+ """
49
+ Liveness probe for Kubernetes.
50
+
51
+ Indicates whether the process is alive and should not be killed.
52
+ Failed liveness = Kubernetes restarts the pod.
53
+
54
+ Should be lightweight and always pass unless process is deadlocked.
55
+ """
56
+
57
+ def __init__(self):
58
+ """Initialize liveness probe."""
59
+ self._custom_checks: list[Callable[[], Union[bool, Awaitable[bool]]]] = []
60
+
61
+ def add_check(self, check: Callable[[], Union[bool, Awaitable[bool]]]) -> None:
62
+ """
63
+ Add custom liveness check.
64
+
65
+ Args:
66
+ check: Sync or async function returning True if healthy
67
+ """
68
+ self._custom_checks.append(check)
69
+
70
+ async def check(self) -> ProbeResult:
71
+ """
72
+ Perform liveness check.
73
+
74
+ Default implementation always returns healthy.
75
+ Override or add custom checks for specific requirements.
76
+ """
77
+ # Run custom checks
78
+ for i, custom_check in enumerate(self._custom_checks):
79
+ try:
80
+ # Handle both sync and async functions
81
+ if asyncio.iscoroutinefunction(custom_check):
82
+ result = await custom_check()
83
+ else:
84
+ result = custom_check()
85
+
86
+ if not result:
87
+ return ProbeResult(
88
+ healthy=False,
89
+ message=f"Custom liveness check {i} failed",
90
+ )
91
+ except Exception as e:
92
+ logger.error(f"Liveness check {i} error: {e}")
93
+ return ProbeResult(
94
+ healthy=False,
95
+ message=f"Custom liveness check {i} error: {e}",
96
+ )
97
+
98
+ return ProbeResult(healthy=True, message="Process is alive")
99
+
100
+
101
+ class ReadinessProbe(HealthProbe):
102
+ """
103
+ Readiness probe for Kubernetes.
104
+
105
+ Indicates whether the process is ready to receive traffic.
106
+ Failed readiness = Kubernetes removes pod from service endpoints.
107
+
108
+ Should check that all dependencies are available.
109
+ """
110
+
111
+ def __init__(self):
112
+ """Initialize readiness probe."""
113
+ self._ready = False
114
+ self._custom_checks: list[Callable[[], Union[bool, Awaitable[bool]]]] = []
115
+
116
+ def mark_ready(self) -> None:
117
+ """Mark the processor as ready to receive traffic."""
118
+ self._ready = True
119
+ logger.info("Processor marked as ready")
120
+
121
+ def mark_not_ready(self) -> None:
122
+ """Mark the processor as not ready."""
123
+ self._ready = False
124
+ logger.info("Processor marked as not ready")
125
+
126
+ def is_ready(self) -> bool:
127
+ """Check if currently marked as ready."""
128
+ return self._ready
129
+
130
+ def add_check(self, check: Callable[[], Union[bool, Awaitable[bool]]]) -> None:
131
+ """
132
+ Add custom readiness check.
133
+
134
+ Args:
135
+ check: Sync or async function returning True if ready
136
+ """
137
+ self._custom_checks.append(check)
138
+
139
+ async def check(self) -> ProbeResult:
140
+ """
141
+ Perform readiness check.
142
+
143
+ Returns not ready until explicitly marked ready.
144
+ Also runs any custom checks.
145
+ """
146
+ if not self._ready:
147
+ return ProbeResult(
148
+ healthy=False,
149
+ message="Processor not yet ready",
150
+ )
151
+
152
+ # Run custom checks
153
+ for i, custom_check in enumerate(self._custom_checks):
154
+ try:
155
+ # Handle both sync and async functions
156
+ if asyncio.iscoroutinefunction(custom_check):
157
+ result = await custom_check()
158
+ else:
159
+ result = custom_check()
160
+
161
+ if not result:
162
+ return ProbeResult(
163
+ healthy=False,
164
+ message=f"Custom readiness check {i} failed",
165
+ )
166
+ except Exception as e:
167
+ logger.error(f"Readiness check {i} error: {e}")
168
+ return ProbeResult(
169
+ healthy=False,
170
+ message=f"Custom readiness check {i} error: {e}",
171
+ )
172
+
173
+ return ProbeResult(healthy=True, message="Processor is ready")
174
+
175
+
176
+ class StartupProbe(HealthProbe):
177
+ """
178
+ Startup probe for Kubernetes.
179
+
180
+ Indicates whether the application has finished starting up.
181
+ Failed startup = Kubernetes keeps waiting (up to failureThreshold).
182
+
183
+ Useful for slow-starting applications.
184
+ """
185
+
186
+ def __init__(self, startup_complete_check: Callable[[], bool] | None = None):
187
+ """
188
+ Initialize startup probe.
189
+
190
+ Args:
191
+ startup_complete_check: Function returning True when startup is complete
192
+ """
193
+ self._startup_complete = False
194
+ self._startup_check = startup_complete_check
195
+
196
+ def mark_startup_complete(self) -> None:
197
+ """Mark startup as complete."""
198
+ self._startup_complete = True
199
+ logger.info("Startup marked as complete")
200
+
201
+ async def check(self) -> ProbeResult:
202
+ """Perform startup check."""
203
+ if self._startup_complete:
204
+ return ProbeResult(healthy=True, message="Startup complete")
205
+
206
+ if self._startup_check and self._startup_check():
207
+ self._startup_complete = True
208
+ return ProbeResult(healthy=True, message="Startup complete")
209
+
210
+ return ProbeResult(healthy=False, message="Still starting up")