kailash 0.5.0__py3-none-any.whl → 0.6.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.
- kailash/__init__.py +1 -1
- kailash/client/__init__.py +12 -0
- kailash/client/enhanced_client.py +306 -0
- kailash/core/actors/__init__.py +16 -0
- kailash/core/actors/connection_actor.py +566 -0
- kailash/core/actors/supervisor.py +364 -0
- kailash/edge/__init__.py +16 -0
- kailash/edge/compliance.py +834 -0
- kailash/edge/discovery.py +659 -0
- kailash/edge/location.py +582 -0
- kailash/gateway/__init__.py +33 -0
- kailash/gateway/api.py +289 -0
- kailash/gateway/enhanced_gateway.py +357 -0
- kailash/gateway/resource_resolver.py +217 -0
- kailash/gateway/security.py +227 -0
- kailash/middleware/auth/models.py +2 -2
- kailash/middleware/database/base_models.py +1 -7
- kailash/middleware/gateway/__init__.py +22 -0
- kailash/middleware/gateway/checkpoint_manager.py +398 -0
- kailash/middleware/gateway/deduplicator.py +382 -0
- kailash/middleware/gateway/durable_gateway.py +417 -0
- kailash/middleware/gateway/durable_request.py +498 -0
- kailash/middleware/gateway/event_store.py +459 -0
- kailash/nodes/admin/permission_check.py +817 -33
- kailash/nodes/admin/role_management.py +1242 -108
- kailash/nodes/admin/schema_manager.py +438 -0
- kailash/nodes/admin/user_management.py +1124 -1582
- kailash/nodes/code/__init__.py +8 -1
- kailash/nodes/code/async_python.py +1035 -0
- kailash/nodes/code/python.py +1 -0
- kailash/nodes/data/async_sql.py +9 -3
- kailash/nodes/data/sql.py +20 -11
- kailash/nodes/data/workflow_connection_pool.py +643 -0
- kailash/nodes/rag/__init__.py +1 -4
- kailash/resources/__init__.py +40 -0
- kailash/resources/factory.py +533 -0
- kailash/resources/health.py +319 -0
- kailash/resources/reference.py +288 -0
- kailash/resources/registry.py +392 -0
- kailash/runtime/async_local.py +711 -302
- kailash/testing/__init__.py +34 -0
- kailash/testing/async_test_case.py +353 -0
- kailash/testing/async_utils.py +345 -0
- kailash/testing/fixtures.py +458 -0
- kailash/testing/mock_registry.py +495 -0
- kailash/workflow/__init__.py +8 -0
- kailash/workflow/async_builder.py +621 -0
- kailash/workflow/async_patterns.py +766 -0
- kailash/workflow/cyclic_runner.py +107 -16
- kailash/workflow/graph.py +7 -2
- kailash/workflow/resilience.py +11 -1
- {kailash-0.5.0.dist-info → kailash-0.6.0.dist-info}/METADATA +7 -4
- {kailash-0.5.0.dist-info → kailash-0.6.0.dist-info}/RECORD +57 -22
- {kailash-0.5.0.dist-info → kailash-0.6.0.dist-info}/WHEEL +0 -0
- {kailash-0.5.0.dist-info → kailash-0.6.0.dist-info}/entry_points.txt +0 -0
- {kailash-0.5.0.dist-info → kailash-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.5.0.dist-info → kailash-0.6.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,319 @@
|
|
1
|
+
"""
|
2
|
+
Health Check System - Monitor and maintain resource health.
|
3
|
+
|
4
|
+
This module provides health checking functionality for resources in the registry,
|
5
|
+
enabling automatic recovery and circuit breaker patterns.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
from dataclasses import dataclass
|
10
|
+
from datetime import datetime
|
11
|
+
from enum import Enum
|
12
|
+
from typing import Any, Dict, Optional, Protocol, Union
|
13
|
+
|
14
|
+
|
15
|
+
class HealthCheckProtocol(Protocol):
|
16
|
+
"""Protocol for health check callables."""
|
17
|
+
|
18
|
+
async def __call__(self, resource: Any) -> Union[bool, "HealthStatus"]:
|
19
|
+
"""
|
20
|
+
Check if a resource is healthy.
|
21
|
+
|
22
|
+
Args:
|
23
|
+
resource: The resource to check
|
24
|
+
|
25
|
+
Returns:
|
26
|
+
bool or HealthStatus indicating health
|
27
|
+
"""
|
28
|
+
...
|
29
|
+
|
30
|
+
|
31
|
+
# Type alias for health checks
|
32
|
+
HealthCheck = HealthCheckProtocol
|
33
|
+
|
34
|
+
|
35
|
+
class HealthState(Enum):
|
36
|
+
"""Health states for resources."""
|
37
|
+
|
38
|
+
HEALTHY = "healthy"
|
39
|
+
DEGRADED = "degraded"
|
40
|
+
UNHEALTHY = "unhealthy"
|
41
|
+
UNKNOWN = "unknown"
|
42
|
+
|
43
|
+
|
44
|
+
@dataclass
|
45
|
+
class HealthStatus:
|
46
|
+
"""
|
47
|
+
Detailed health status for a resource.
|
48
|
+
|
49
|
+
This provides more information than a simple boolean,
|
50
|
+
allowing for degraded states and detailed diagnostics.
|
51
|
+
"""
|
52
|
+
|
53
|
+
state: HealthState
|
54
|
+
message: Optional[str] = None
|
55
|
+
details: Optional[Dict[str, Any]] = None
|
56
|
+
timestamp: datetime = None
|
57
|
+
|
58
|
+
def __post_init__(self):
|
59
|
+
if self.timestamp is None:
|
60
|
+
self.timestamp = datetime.now()
|
61
|
+
|
62
|
+
@property
|
63
|
+
def is_healthy(self) -> bool:
|
64
|
+
"""Check if status indicates health."""
|
65
|
+
return self.state in (HealthState.HEALTHY, HealthState.DEGRADED)
|
66
|
+
|
67
|
+
@classmethod
|
68
|
+
def healthy(cls, message: str = "Resource is healthy") -> "HealthStatus":
|
69
|
+
"""Create a healthy status."""
|
70
|
+
return cls(HealthState.HEALTHY, message)
|
71
|
+
|
72
|
+
@classmethod
|
73
|
+
def unhealthy(cls, message: str, details: Dict[str, Any] = None) -> "HealthStatus":
|
74
|
+
"""Create an unhealthy status."""
|
75
|
+
return cls(HealthState.UNHEALTHY, message, details)
|
76
|
+
|
77
|
+
@classmethod
|
78
|
+
def degraded(cls, message: str, details: Dict[str, Any] = None) -> "HealthStatus":
|
79
|
+
"""Create a degraded status."""
|
80
|
+
return cls(HealthState.DEGRADED, message, details)
|
81
|
+
|
82
|
+
|
83
|
+
# Common health checks
|
84
|
+
|
85
|
+
|
86
|
+
async def database_health_check(pool) -> HealthStatus:
|
87
|
+
"""
|
88
|
+
Health check for database connection pools.
|
89
|
+
|
90
|
+
Args:
|
91
|
+
pool: Database connection pool
|
92
|
+
|
93
|
+
Returns:
|
94
|
+
HealthStatus indicating database health
|
95
|
+
"""
|
96
|
+
try:
|
97
|
+
# Try to acquire a connection
|
98
|
+
if hasattr(pool, "acquire"):
|
99
|
+
# asyncpg style
|
100
|
+
async with pool.acquire() as conn:
|
101
|
+
# Try a simple query
|
102
|
+
if hasattr(conn, "fetchval"):
|
103
|
+
await conn.fetchval("SELECT 1")
|
104
|
+
elif hasattr(conn, "execute"):
|
105
|
+
await conn.execute("SELECT 1")
|
106
|
+
elif hasattr(pool, "ping"):
|
107
|
+
# Some pools have a ping method
|
108
|
+
await pool.ping()
|
109
|
+
elif hasattr(pool, "execute"):
|
110
|
+
# aiosqlite style
|
111
|
+
await pool.execute("SELECT 1")
|
112
|
+
|
113
|
+
return HealthStatus.healthy("Database connection is healthy")
|
114
|
+
|
115
|
+
except asyncio.TimeoutError:
|
116
|
+
return HealthStatus.unhealthy(
|
117
|
+
"Database connection timed out", {"error": "timeout"}
|
118
|
+
)
|
119
|
+
except Exception as e:
|
120
|
+
return HealthStatus.unhealthy(
|
121
|
+
f"Database health check failed: {str(e)}",
|
122
|
+
{"error": str(e), "type": type(e).__name__},
|
123
|
+
)
|
124
|
+
|
125
|
+
|
126
|
+
async def http_client_health_check(
|
127
|
+
client, health_endpoint: str = "/health"
|
128
|
+
) -> HealthStatus:
|
129
|
+
"""
|
130
|
+
Health check for HTTP clients.
|
131
|
+
|
132
|
+
Args:
|
133
|
+
client: HTTP client (aiohttp or httpx)
|
134
|
+
health_endpoint: Endpoint to check
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
HealthStatus indicating HTTP client health
|
138
|
+
"""
|
139
|
+
try:
|
140
|
+
# Handle different client types
|
141
|
+
if hasattr(client, "get"):
|
142
|
+
# aiohttp or httpx style
|
143
|
+
if hasattr(client, "_base_url"):
|
144
|
+
# httpx
|
145
|
+
response = await client.get(health_endpoint)
|
146
|
+
status_code = response.status_code
|
147
|
+
else:
|
148
|
+
# aiohttp
|
149
|
+
async with client.get(health_endpoint) as response:
|
150
|
+
status_code = response.status
|
151
|
+
|
152
|
+
if 200 <= status_code < 300:
|
153
|
+
return HealthStatus.healthy(
|
154
|
+
f"HTTP client is healthy (status: {status_code})"
|
155
|
+
)
|
156
|
+
else:
|
157
|
+
return HealthStatus.unhealthy(
|
158
|
+
f"HTTP health check returned {status_code}",
|
159
|
+
{"status_code": status_code},
|
160
|
+
)
|
161
|
+
else:
|
162
|
+
# Unknown client type, assume healthy
|
163
|
+
return HealthStatus.healthy(
|
164
|
+
"HTTP client type not recognized, assuming healthy"
|
165
|
+
)
|
166
|
+
|
167
|
+
except asyncio.TimeoutError:
|
168
|
+
return HealthStatus.unhealthy(
|
169
|
+
"HTTP health check timed out", {"error": "timeout"}
|
170
|
+
)
|
171
|
+
except Exception as e:
|
172
|
+
return HealthStatus.unhealthy(
|
173
|
+
f"HTTP health check failed: {str(e)}",
|
174
|
+
{"error": str(e), "type": type(e).__name__},
|
175
|
+
)
|
176
|
+
|
177
|
+
|
178
|
+
async def cache_health_check(cache) -> HealthStatus:
|
179
|
+
"""
|
180
|
+
Health check for cache clients.
|
181
|
+
|
182
|
+
Args:
|
183
|
+
cache: Cache client (Redis, Memcached, etc.)
|
184
|
+
|
185
|
+
Returns:
|
186
|
+
HealthStatus indicating cache health
|
187
|
+
"""
|
188
|
+
try:
|
189
|
+
test_key = "_health_check_test"
|
190
|
+
test_value = "healthy"
|
191
|
+
|
192
|
+
# Try to set and get a value
|
193
|
+
if hasattr(cache, "set") and hasattr(cache, "get"):
|
194
|
+
await cache.set(test_key, test_value)
|
195
|
+
result = await cache.get(test_key)
|
196
|
+
|
197
|
+
if result == test_value or (
|
198
|
+
isinstance(result, bytes) and result.decode() == test_value
|
199
|
+
):
|
200
|
+
# Clean up
|
201
|
+
if hasattr(cache, "delete"):
|
202
|
+
await cache.delete(test_key)
|
203
|
+
return HealthStatus.healthy("Cache is healthy")
|
204
|
+
else:
|
205
|
+
return HealthStatus.unhealthy(
|
206
|
+
"Cache health check failed: value mismatch",
|
207
|
+
{"expected": test_value, "got": result},
|
208
|
+
)
|
209
|
+
elif hasattr(cache, "ping"):
|
210
|
+
# Redis style ping
|
211
|
+
await cache.ping()
|
212
|
+
return HealthStatus.healthy("Cache is healthy (ping successful)")
|
213
|
+
else:
|
214
|
+
# Unknown cache type
|
215
|
+
return HealthStatus.healthy("Cache type not recognized, assuming healthy")
|
216
|
+
|
217
|
+
except asyncio.TimeoutError:
|
218
|
+
return HealthStatus.unhealthy(
|
219
|
+
"Cache health check timed out", {"error": "timeout"}
|
220
|
+
)
|
221
|
+
except Exception as e:
|
222
|
+
return HealthStatus.unhealthy(
|
223
|
+
f"Cache health check failed: {str(e)}",
|
224
|
+
{"error": str(e), "type": type(e).__name__},
|
225
|
+
)
|
226
|
+
|
227
|
+
|
228
|
+
async def message_queue_health_check(mq) -> HealthStatus:
|
229
|
+
"""
|
230
|
+
Health check for message queue clients.
|
231
|
+
|
232
|
+
Args:
|
233
|
+
mq: Message queue client
|
234
|
+
|
235
|
+
Returns:
|
236
|
+
HealthStatus indicating message queue health
|
237
|
+
"""
|
238
|
+
try:
|
239
|
+
# RabbitMQ (aio-pika)
|
240
|
+
if hasattr(mq, "channel"):
|
241
|
+
channel = await mq.channel()
|
242
|
+
await channel.close()
|
243
|
+
return HealthStatus.healthy(
|
244
|
+
"Message queue is healthy (channel test successful)"
|
245
|
+
)
|
246
|
+
|
247
|
+
# Kafka
|
248
|
+
elif hasattr(mq, "producer") and hasattr(mq, "consumer"):
|
249
|
+
# Custom Kafka client from factory
|
250
|
+
# Just check if they exist
|
251
|
+
return HealthStatus.healthy("Kafka clients are healthy")
|
252
|
+
|
253
|
+
# Generic check
|
254
|
+
elif hasattr(mq, "is_closed"):
|
255
|
+
if not mq.is_closed:
|
256
|
+
return HealthStatus.healthy("Message queue connection is open")
|
257
|
+
else:
|
258
|
+
return HealthStatus.unhealthy("Message queue connection is closed")
|
259
|
+
|
260
|
+
else:
|
261
|
+
# Unknown MQ type
|
262
|
+
return HealthStatus.healthy(
|
263
|
+
"Message queue type not recognized, assuming healthy"
|
264
|
+
)
|
265
|
+
|
266
|
+
except asyncio.TimeoutError:
|
267
|
+
return HealthStatus.unhealthy(
|
268
|
+
"Message queue health check timed out", {"error": "timeout"}
|
269
|
+
)
|
270
|
+
except Exception as e:
|
271
|
+
return HealthStatus.unhealthy(
|
272
|
+
f"Message queue health check failed: {str(e)}",
|
273
|
+
{"error": str(e), "type": type(e).__name__},
|
274
|
+
)
|
275
|
+
|
276
|
+
|
277
|
+
def create_composite_health_check(*checks: HealthCheck) -> HealthCheck:
|
278
|
+
"""
|
279
|
+
Create a composite health check from multiple checks.
|
280
|
+
|
281
|
+
All checks must pass for the resource to be considered healthy.
|
282
|
+
|
283
|
+
Args:
|
284
|
+
*checks: Health check functions
|
285
|
+
|
286
|
+
Returns:
|
287
|
+
Composite health check function
|
288
|
+
|
289
|
+
Example:
|
290
|
+
```python
|
291
|
+
health_check = create_composite_health_check(
|
292
|
+
lambda r: database_health_check(r.db),
|
293
|
+
lambda r: cache_health_check(r.cache)
|
294
|
+
)
|
295
|
+
```
|
296
|
+
"""
|
297
|
+
|
298
|
+
async def composite_check(resource: Any) -> HealthStatus:
|
299
|
+
results = []
|
300
|
+
|
301
|
+
for check in checks:
|
302
|
+
try:
|
303
|
+
result = await check(resource)
|
304
|
+
if isinstance(result, bool):
|
305
|
+
if not result:
|
306
|
+
return HealthStatus.unhealthy("Composite check failed")
|
307
|
+
elif isinstance(result, HealthStatus):
|
308
|
+
if not result.is_healthy:
|
309
|
+
return result
|
310
|
+
results.append(result)
|
311
|
+
except Exception as e:
|
312
|
+
return HealthStatus.unhealthy(
|
313
|
+
f"Health check error: {str(e)}", {"error": str(e)}
|
314
|
+
)
|
315
|
+
|
316
|
+
# All checks passed
|
317
|
+
return HealthStatus.healthy("All health checks passed")
|
318
|
+
|
319
|
+
return composite_check
|
@@ -0,0 +1,288 @@
|
|
1
|
+
"""
|
2
|
+
Resource References - JSON-serializable references to resources.
|
3
|
+
|
4
|
+
This module enables resources to be referenced in JSON APIs by providing
|
5
|
+
a serializable reference format.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import json
|
9
|
+
from dataclasses import asdict, dataclass
|
10
|
+
from typing import Any, Dict, Optional
|
11
|
+
|
12
|
+
|
13
|
+
@dataclass
|
14
|
+
class ResourceReference:
|
15
|
+
"""
|
16
|
+
Reference to a resource that can be resolved by the gateway.
|
17
|
+
|
18
|
+
This class provides a JSON-serializable way to reference resources
|
19
|
+
in API calls, solving the problem of passing non-serializable objects.
|
20
|
+
|
21
|
+
Example:
|
22
|
+
```python
|
23
|
+
# Create a reference to a database
|
24
|
+
db_ref = ResourceReference(
|
25
|
+
type="database",
|
26
|
+
config={
|
27
|
+
"host": "localhost",
|
28
|
+
"database": "myapp"
|
29
|
+
},
|
30
|
+
credentials_ref="db_credentials"
|
31
|
+
)
|
32
|
+
|
33
|
+
# Convert to JSON
|
34
|
+
json_ref = db_ref.to_json()
|
35
|
+
|
36
|
+
# Use in API call
|
37
|
+
response = await client.execute_workflow(
|
38
|
+
workflow_id="process_data",
|
39
|
+
inputs={"data": [1, 2, 3]},
|
40
|
+
resources={"db": db_ref}
|
41
|
+
)
|
42
|
+
```
|
43
|
+
|
44
|
+
Attributes:
|
45
|
+
type: The type of resource (database, http_client, cache, etc.)
|
46
|
+
config: Configuration parameters for the resource
|
47
|
+
credentials_ref: Optional reference to credentials in secret manager
|
48
|
+
name: Optional name to reference a pre-registered resource
|
49
|
+
"""
|
50
|
+
|
51
|
+
type: str
|
52
|
+
config: Dict[str, Any]
|
53
|
+
credentials_ref: Optional[str] = None
|
54
|
+
name: Optional[str] = None
|
55
|
+
|
56
|
+
def to_dict(self) -> Dict[str, Any]:
|
57
|
+
"""
|
58
|
+
Convert to JSON-serializable dictionary.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
Dictionary representation of the reference
|
62
|
+
"""
|
63
|
+
data = {"type": self.type, "config": self.config}
|
64
|
+
|
65
|
+
if self.credentials_ref:
|
66
|
+
data["credentials_ref"] = self.credentials_ref
|
67
|
+
|
68
|
+
if self.name:
|
69
|
+
data["name"] = self.name
|
70
|
+
|
71
|
+
return data
|
72
|
+
|
73
|
+
def to_json(self) -> str:
|
74
|
+
"""
|
75
|
+
Convert to JSON string.
|
76
|
+
|
77
|
+
Returns:
|
78
|
+
JSON string representation
|
79
|
+
"""
|
80
|
+
return json.dumps(self.to_dict())
|
81
|
+
|
82
|
+
@classmethod
|
83
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ResourceReference":
|
84
|
+
"""
|
85
|
+
Create from dictionary.
|
86
|
+
|
87
|
+
Args:
|
88
|
+
data: Dictionary with reference data
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
ResourceReference instance
|
92
|
+
"""
|
93
|
+
return cls(
|
94
|
+
type=data["type"],
|
95
|
+
config=data["config"],
|
96
|
+
credentials_ref=data.get("credentials_ref"),
|
97
|
+
name=data.get("name"),
|
98
|
+
)
|
99
|
+
|
100
|
+
@classmethod
|
101
|
+
def from_json(cls, json_str: str) -> "ResourceReference":
|
102
|
+
"""
|
103
|
+
Create from JSON string.
|
104
|
+
|
105
|
+
Args:
|
106
|
+
json_str: JSON string representation
|
107
|
+
|
108
|
+
Returns:
|
109
|
+
ResourceReference instance
|
110
|
+
"""
|
111
|
+
return cls.from_dict(json.loads(json_str))
|
112
|
+
|
113
|
+
@classmethod
|
114
|
+
def for_registered_resource(cls, name: str) -> "ResourceReference":
|
115
|
+
"""
|
116
|
+
Create a reference to a pre-registered resource.
|
117
|
+
|
118
|
+
This is a shorthand for referencing resources that are already
|
119
|
+
registered in the ResourceRegistry.
|
120
|
+
|
121
|
+
Args:
|
122
|
+
name: Name of the registered resource
|
123
|
+
|
124
|
+
Returns:
|
125
|
+
ResourceReference instance
|
126
|
+
|
127
|
+
Example:
|
128
|
+
```python
|
129
|
+
# Reference a pre-registered database
|
130
|
+
db_ref = ResourceReference.for_registered_resource("main_db")
|
131
|
+
```
|
132
|
+
"""
|
133
|
+
return cls(type="registered", config={}, name=name)
|
134
|
+
|
135
|
+
|
136
|
+
def create_database_reference(
|
137
|
+
host: str,
|
138
|
+
database: str,
|
139
|
+
backend: str = "postgresql",
|
140
|
+
port: Optional[int] = None,
|
141
|
+
credentials_ref: Optional[str] = None,
|
142
|
+
**kwargs,
|
143
|
+
) -> ResourceReference:
|
144
|
+
"""
|
145
|
+
Helper to create a database resource reference.
|
146
|
+
|
147
|
+
Args:
|
148
|
+
host: Database host
|
149
|
+
database: Database name
|
150
|
+
backend: Database backend (postgresql, mysql, sqlite)
|
151
|
+
port: Database port (uses default if not specified)
|
152
|
+
credentials_ref: Reference to credentials in secret manager
|
153
|
+
**kwargs: Additional configuration
|
154
|
+
|
155
|
+
Returns:
|
156
|
+
ResourceReference for a database
|
157
|
+
|
158
|
+
Example:
|
159
|
+
```python
|
160
|
+
db_ref = create_database_reference(
|
161
|
+
host="db.example.com",
|
162
|
+
database="production",
|
163
|
+
credentials_ref="prod_db_creds"
|
164
|
+
)
|
165
|
+
```
|
166
|
+
"""
|
167
|
+
config = {"backend": backend, "host": host, "database": database, **kwargs}
|
168
|
+
|
169
|
+
if port:
|
170
|
+
config["port"] = port
|
171
|
+
|
172
|
+
return ResourceReference(
|
173
|
+
type="database", config=config, credentials_ref=credentials_ref
|
174
|
+
)
|
175
|
+
|
176
|
+
|
177
|
+
def create_http_client_reference(
|
178
|
+
base_url: str,
|
179
|
+
backend: str = "aiohttp",
|
180
|
+
timeout: int = 30,
|
181
|
+
credentials_ref: Optional[str] = None,
|
182
|
+
headers: Optional[Dict[str, str]] = None,
|
183
|
+
**kwargs,
|
184
|
+
) -> ResourceReference:
|
185
|
+
"""
|
186
|
+
Helper to create an HTTP client resource reference.
|
187
|
+
|
188
|
+
Args:
|
189
|
+
base_url: Base URL for the HTTP client
|
190
|
+
backend: HTTP client backend (aiohttp, httpx)
|
191
|
+
timeout: Request timeout in seconds
|
192
|
+
credentials_ref: Reference to credentials for auth headers
|
193
|
+
headers: Additional headers
|
194
|
+
**kwargs: Additional configuration
|
195
|
+
|
196
|
+
Returns:
|
197
|
+
ResourceReference for an HTTP client
|
198
|
+
|
199
|
+
Example:
|
200
|
+
```python
|
201
|
+
api_ref = create_http_client_reference(
|
202
|
+
base_url="https://api.example.com",
|
203
|
+
timeout=60,
|
204
|
+
credentials_ref="api_key"
|
205
|
+
)
|
206
|
+
```
|
207
|
+
"""
|
208
|
+
config = {"backend": backend, "base_url": base_url, "timeout": timeout, **kwargs}
|
209
|
+
|
210
|
+
if headers:
|
211
|
+
config["headers"] = headers
|
212
|
+
|
213
|
+
return ResourceReference(
|
214
|
+
type="http_client", config=config, credentials_ref=credentials_ref
|
215
|
+
)
|
216
|
+
|
217
|
+
|
218
|
+
def create_cache_reference(
|
219
|
+
backend: str = "redis",
|
220
|
+
host: str = "localhost",
|
221
|
+
port: Optional[int] = None,
|
222
|
+
**kwargs,
|
223
|
+
) -> ResourceReference:
|
224
|
+
"""
|
225
|
+
Helper to create a cache resource reference.
|
226
|
+
|
227
|
+
Args:
|
228
|
+
backend: Cache backend (redis, memcached, memory)
|
229
|
+
host: Cache server host
|
230
|
+
port: Cache server port
|
231
|
+
**kwargs: Additional configuration
|
232
|
+
|
233
|
+
Returns:
|
234
|
+
ResourceReference for a cache
|
235
|
+
|
236
|
+
Example:
|
237
|
+
```python
|
238
|
+
cache_ref = create_cache_reference(
|
239
|
+
backend="redis",
|
240
|
+
host="cache.example.com"
|
241
|
+
)
|
242
|
+
```
|
243
|
+
"""
|
244
|
+
config = {"backend": backend, "host": host, **kwargs}
|
245
|
+
|
246
|
+
if port:
|
247
|
+
config["port"] = port
|
248
|
+
|
249
|
+
return ResourceReference(type="cache", config=config)
|
250
|
+
|
251
|
+
|
252
|
+
def create_message_queue_reference(
|
253
|
+
backend: str,
|
254
|
+
host: str = "localhost",
|
255
|
+
port: Optional[int] = None,
|
256
|
+
credentials_ref: Optional[str] = None,
|
257
|
+
**kwargs,
|
258
|
+
) -> ResourceReference:
|
259
|
+
"""
|
260
|
+
Helper to create a message queue resource reference.
|
261
|
+
|
262
|
+
Args:
|
263
|
+
backend: Message queue backend (rabbitmq, kafka, redis)
|
264
|
+
host: Message queue host
|
265
|
+
port: Message queue port
|
266
|
+
credentials_ref: Reference to credentials
|
267
|
+
**kwargs: Additional configuration
|
268
|
+
|
269
|
+
Returns:
|
270
|
+
ResourceReference for a message queue
|
271
|
+
|
272
|
+
Example:
|
273
|
+
```python
|
274
|
+
mq_ref = create_message_queue_reference(
|
275
|
+
backend="rabbitmq",
|
276
|
+
host="mq.example.com",
|
277
|
+
credentials_ref="mq_creds"
|
278
|
+
)
|
279
|
+
```
|
280
|
+
"""
|
281
|
+
config = {"backend": backend, "host": host, **kwargs}
|
282
|
+
|
283
|
+
if port:
|
284
|
+
config["port"] = port
|
285
|
+
|
286
|
+
return ResourceReference(
|
287
|
+
type="message_queue", config=config, credentials_ref=credentials_ref
|
288
|
+
)
|