Skip to content

Commit 9bfff95

Browse files
author
Remy Gwaramadze
committed
Improve dynamic configuration docs
1 parent 0f17707 commit 9bfff95

File tree

1 file changed

+332
-8
lines changed

1 file changed

+332
-8
lines changed

docs/quix-cloud/managed-services/dynamic-configuration.md

Lines changed: 332 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,338 @@ This service can leverage a blob storage configured on our platform (see [blob s
132132

133133
The blob storage configuration is automatically injected only when `contentStore` is set to `file`.
134134

135-
## SDK Integration
135+
## API Reference
136136

137-
The **Quix Streams SDK** provides built-in functionality to:
137+
The Dynamic Configuration Manager provides a REST API for managing configurations. The API is available at the service endpoint once deployed.
138138

139-
- Subscribe to configuration change events.
140-
- Download and cache the latest configuration from the API.
141-
- Join configuration values with live data streams at the right time.
139+
### Base URL
140+
```
141+
http://<service-name>:<port>/api/v1
142+
```
143+
144+
### Authentication
145+
All API requests require authentication via the `Authorization` header:
146+
```
147+
Authorization: Bearer <your-token>
148+
```
149+
150+
### Create Configuration
151+
152+
Create a new configuration:
153+
154+
```http
155+
POST /api/v1/configurations
156+
Content-Type: application/json
157+
158+
{
159+
"metadata": {
160+
"type": "device-config",
161+
"target_key": "sensor-001",
162+
"valid_from": "2024-01-01T00:00:00Z",
163+
"category": "sensors"
164+
},
165+
"content": {
166+
"device": {
167+
"name": "Temperature Sensor 001",
168+
"model": "TS-2000",
169+
"location": "Building A, Floor 2"
170+
},
171+
"calibration": {
172+
"offset": 0.5,
173+
"scale": 1.02,
174+
"last_calibrated": "2024-01-01T00:00:00Z"
175+
},
176+
"firmware": {
177+
"version": "2.1.3",
178+
"features": ["temperature", "humidity"]
179+
}
180+
},
181+
"replace": false
182+
}
183+
```
184+
185+
**Request Body:**
186+
- `metadata.type` (string, required): Configuration type identifier
187+
- `metadata.target_key` (string, required): Target key for configuration matching
188+
- `metadata.valid_from` (ISO8601 datetime, optional): When this configuration becomes valid
189+
- `metadata.category` (string, optional): Category for grouping configurations
190+
- `content` (object, optional): The actual configuration data (JSON object)
191+
- `replace` (boolean, optional): If true, creates a new version if configuration already exists (default: false)
192+
193+
**Note:** The configuration `id` is automatically generated from `type` and `target_key` using SHA-1 hash.
194+
195+
### Update Configuration
196+
197+
Update an existing configuration (creates a new version):
198+
199+
```http
200+
PUT /api/v1/configurations/{id}
201+
Content-Type: application/json
202+
203+
{
204+
"metadata": {
205+
"valid_from": "2024-01-15T00:00:00Z",
206+
"category": "sensors"
207+
},
208+
"content": {
209+
"device": {
210+
"name": "Temperature Sensor 001",
211+
"model": "TS-2000",
212+
"location": "Building A, Floor 3"
213+
},
214+
"calibration": {
215+
"offset": 0.3,
216+
"scale": 1.01,
217+
"last_calibrated": "2024-01-15T10:30:00Z"
218+
}
219+
}
220+
}
221+
```
222+
223+
**Request Body:**
224+
- `metadata.valid_from` (ISO8601 datetime, optional): Update when this configuration becomes valid
225+
- `metadata.category` (string, optional): Update the category
226+
- `content` (object, optional): Updated configuration data
227+
228+
**Note:** Only fields you provide will be updated. Omitted fields remain unchanged.
229+
230+
### Upload Binary Configuration
231+
232+
For non-JSON configurations (firmware files, calibration data, etc.), use the file upload endpoint:
233+
234+
```http
235+
POST /api/v1/configurations/{id}/versions/{version}/content
236+
Content-Type: multipart/form-data
237+
238+
file: <binary-file-data>
239+
```
240+
241+
**Note:** Binary content must be uploaded separately after creating the configuration metadata. The service automatically detects and stores binary content with appropriate `content_type`.
242+
243+
### Search Configurations
244+
245+
Search for configurations using various criteria:
246+
247+
```http
248+
GET /api/v1/configurations/search?type=device-config&target_key=sensor-001&limit=10&offset=0
249+
```
250+
251+
**Query Parameters:**
252+
- `type` (string, optional): Filter by configuration type
253+
- `target_key` (string, optional): Filter by target key
254+
- `category` (string, optional): Filter by category
255+
- `limit` (integer, optional): Maximum number of results (default: 20)
256+
- `offset` (integer, optional): Number of results to skip (default: 0)
257+
258+
### Get Configuration
259+
260+
Retrieve a specific configuration:
261+
262+
```http
263+
GET /api/v1/configurations/{id}
264+
```
265+
266+
### Get Configuration Version
267+
268+
Retrieve a specific version of a configuration:
269+
270+
```http
271+
GET /api/v1/configurations/{id}/versions/{version}
272+
```
273+
274+
### Delete Configuration
275+
276+
Delete a configuration (all versions):
277+
278+
```http
279+
DELETE /api/v1/configurations/{id}
280+
```
281+
282+
### Storage Modes
283+
284+
#### MongoDB Mode (Default)
285+
- **Content Type**: JSON only
286+
- **Size Limit**: 16 MB per configuration
287+
- **Use Case**: Structured configuration data
288+
- **Setup**: Configure MongoDB connection parameters
289+
290+
#### File Mode (Blob Storage)
291+
- **Content Type**: Any binary data
292+
- **Size Limit**: Depends on blob storage provider
293+
- **Use Case**: Large files, firmware, binary data
294+
- **Setup**: Configure blob storage credentials
295+
296+
To use file mode, set `contentStore: file` in your deployment configuration.
297+
298+
## Using with Quix Streams join_lookup
299+
300+
The Dynamic Configuration Manager integrates seamlessly with Quix Streams' `join_lookup` feature to enrich streaming data with configuration data in real-time.
301+
302+
### Basic Integration
303+
304+
```python
305+
from quixstreams import Application
306+
from quixstreams.dataframe.joins.lookups import QuixConfigurationService
307+
308+
# Initialize the application
309+
app = Application()
310+
311+
# Create a lookup instance pointing to your configuration topic
312+
lookup = QuixConfigurationService(
313+
topic=app.topic("device-configurations"),
314+
app_config=app.config
315+
)
316+
317+
# Create your main data stream
318+
sdf = app.dataframe(app.topic("sensor-data"))
319+
320+
# Enrich sensor data with device configuration
321+
sdf = sdf.join_lookup(
322+
lookup=lookup,
323+
fields={
324+
"device_name": lookup.json_field(
325+
jsonpath="$.device.name",
326+
type="device-config"
327+
),
328+
"calibration_params": lookup.json_field(
329+
jsonpath="$.calibration",
330+
type="device-config"
331+
),
332+
"firmware_version": lookup.json_field(
333+
jsonpath="$.firmware.version",
334+
type="device-config"
335+
)
336+
},
337+
on="device_id" # The field to match on
338+
)
339+
340+
# Process the enriched data
341+
sdf = sdf.apply(lambda value: {
342+
**value,
343+
"device_info": f"{value['device_name']} (v{value['firmware_version']})"
344+
})
345+
346+
# Output to destination topic
347+
sdf.to_topic(app.topic("enriched-sensor-data"))
348+
349+
if __name__ == "__main__":
350+
app.run()
351+
```
352+
353+
### Advanced Configuration Matching
354+
355+
Use custom key matching logic for complex scenarios:
356+
357+
```python
358+
def custom_key_matcher(value, key):
359+
"""Custom logic to determine configuration key"""
360+
device_type = value.get("device_type", "unknown")
361+
location = value.get("location", "default")
362+
return f"{device_type}-{location}"
363+
364+
# Use custom key matching
365+
sdf = sdf.join_lookup(
366+
lookup=lookup,
367+
fields={
368+
"config": lookup.json_field(
369+
jsonpath="$",
370+
type="location-config"
371+
)
372+
},
373+
on=custom_key_matcher
374+
)
375+
```
376+
377+
### Binary Configuration Support
378+
379+
For non-JSON configurations (firmware files, calibration data, etc.):
380+
381+
```python
382+
sdf = sdf.join_lookup(
383+
lookup=lookup,
384+
fields={
385+
"firmware_binary": lookup.bytes_field(
386+
type="firmware"
387+
),
388+
"calibration_data": lookup.bytes_field(
389+
type="calibration"
390+
)
391+
},
392+
on="device_id"
393+
)
394+
```
395+
396+
### How join_lookup Works with Dynamic Configuration
397+
398+
1. **Configuration Events**: When configurations are updated via the API, lightweight Kafka events are published to your configuration topic.
399+
400+
2. **Real-time Processing**: The `join_lookup` feature listens to these events, fetches the latest configuration content, and caches it locally.
401+
402+
3. **Stream Enrichment**: As your main data stream processes records, `join_lookup` automatically enriches each record with the appropriate configuration data based on the matching key and timestamp.
403+
404+
4. **Version Management**: The system automatically handles configuration versioning, ensuring that each record is enriched with the configuration version that was valid at the time the record was created.
405+
406+
5. **Performance Optimization**: Local caching minimizes API calls and reduces latency for high-throughput applications.
407+
408+
### Advanced Use Cases
409+
410+
#### Custom Target Key Matching
411+
412+
For complex matching logic that goes beyond simple field matching:
413+
414+
```python
415+
class CustomLookup(QuixConfigurationService):
416+
def _config_id(self, type: str, key: str) -> str:
417+
"""Override to implement custom ID generation"""
418+
# Custom logic for generating configuration IDs
419+
if type == "device-config":
420+
# Extract device type and location from key
421+
parts = key.split("-")
422+
device_type = parts[0]
423+
location = parts[1] if len(parts) > 1 else "default"
424+
return f"{device_type}-{location}"
425+
return super()._config_id(type, key)
426+
427+
# Use custom lookup
428+
custom_lookup = CustomLookup(
429+
topic=app.topic("device-configurations"),
430+
app_config=app.config
431+
)
432+
```
433+
434+
#### Multi-Type Configuration Enrichment
435+
436+
Enrich with multiple configuration types:
437+
438+
```python
439+
sdf = sdf.join_lookup(
440+
lookup=lookup,
441+
fields={
442+
# Device configuration
443+
"device_info": lookup.json_field(
444+
jsonpath="$.device",
445+
type="device-config"
446+
),
447+
# Location configuration
448+
"location_info": lookup.json_field(
449+
jsonpath="$.location",
450+
type="location-config"
451+
),
452+
# Calibration data
453+
"calibration": lookup.json_field(
454+
jsonpath="$",
455+
type="calibration-config"
456+
)
457+
},
458+
on="device_id"
459+
)
460+
```
461+
462+
### Benefits
142463

143-
👉 See [SDK
144-
documentation](../../quix-streams/api-reference/dataframe.html#streamingdataframejoin_lookup)
145-
for details on `join_lookup` and related features.
464+
- **Real-time Updates**: Configuration changes are immediately available to your streaming applications
465+
- **Large File Support**: Handle configuration files too large for direct Kafka streaming
466+
- **Version Control**: Automatic versioning ensures data consistency
467+
- **Performance**: Local caching minimizes API calls and latency
468+
- **Flexibility**: Support for both JSON and binary configuration content
469+
- **Scalability**: Efficient handling of high-throughput data streams

0 commit comments

Comments
 (0)