avtomatika-worker 1.0b2__tar.gz → 1.0b4__tar.gz
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.
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/LICENSE +1 -1
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/PKG-INFO +80 -11
- avtomatika_worker-1.0b2/src/avtomatika_worker.egg-info/PKG-INFO → avtomatika_worker-1.0b4/README.md +72 -36
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/pyproject.toml +13 -2
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker/__init__.py +1 -1
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker/config.py +20 -1
- avtomatika_worker-1.0b4/src/avtomatika_worker/py.typed +0 -0
- avtomatika_worker-1.0b4/src/avtomatika_worker/s3.py +238 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker/task_files.py +60 -2
- avtomatika_worker-1.0b4/src/avtomatika_worker/types.py +26 -0
- avtomatika_worker-1.0b4/src/avtomatika_worker/worker.py +704 -0
- avtomatika_worker-1.0b2/README.md → avtomatika_worker-1.0b4/src/avtomatika_worker.egg-info/PKG-INFO +105 -9
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker.egg-info/SOURCES.txt +3 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker.egg-info/requires.txt +3 -1
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_dependency_injection.py +5 -2
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_parameter_typing.py +28 -31
- avtomatika_worker-1.0b4/tests/test_s3.py +221 -0
- avtomatika_worker-1.0b4/tests/test_task_files_extended.py +60 -0
- avtomatika_worker-1.0b4/tests/test_validation.py +57 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_worker_logic.py +66 -56
- avtomatika_worker-1.0b4/tests/test_worker_more_logic.py +211 -0
- avtomatika_worker-1.0b4/tests/test_worker_sdk.py +281 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_wrr_logic.py +13 -7
- avtomatika_worker-1.0b2/src/avtomatika_worker/s3.py +0 -141
- avtomatika_worker-1.0b2/src/avtomatika_worker/types.py +0 -8
- avtomatika_worker-1.0b2/src/avtomatika_worker/worker.py +0 -541
- avtomatika_worker-1.0b2/tests/test_s3.py +0 -179
- avtomatika_worker-1.0b2/tests/test_worker_more_logic.py +0 -272
- avtomatika_worker-1.0b2/tests/test_worker_sdk.py +0 -395
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/setup.cfg +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker.egg-info/dependency_links.txt +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/src/avtomatika_worker.egg-info/top_level.txt +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_concurrency_limits.py +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_config.py +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_init.py +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_per_orchestrator_token.py +0 -0
- {avtomatika_worker-1.0b2 → avtomatika_worker-1.0b4}/tests/test_types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 Dmitrii Gagarin
|
|
3
|
+
Copyright (c) 2025-2026 Dmitrii Gagarin aka madgagarin
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: avtomatika-worker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.0b4
|
|
4
4
|
Summary: Worker SDK for the Avtomatika orchestrator.
|
|
5
|
+
Author-email: Dmitrii Gagarin <madgagarin@gmail.com>
|
|
5
6
|
Project-URL: Homepage, https://github.com/avtomatika-ai/avtomatika-worker
|
|
6
7
|
Project-URL: Bug Tracker, https://github.com/avtomatika-ai/avtomatika-worker/issues
|
|
8
|
+
Keywords: worker,sdk,orchestrator,distributed,task-queue,rxon,hln
|
|
7
9
|
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
8
11
|
Classifier: Programming Language :: Python :: 3
|
|
9
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
13
|
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Typing :: Typed
|
|
11
15
|
Requires-Python: >=3.11
|
|
12
16
|
Description-Content-Type: text/markdown
|
|
13
17
|
License-File: LICENSE
|
|
18
|
+
Requires-Dist: rxon==1.0b2
|
|
14
19
|
Requires-Dist: aiohttp~=3.13.2
|
|
15
20
|
Requires-Dist: python-json-logger~=4.0.0
|
|
16
|
-
Requires-Dist:
|
|
21
|
+
Requires-Dist: obstore>=0.1
|
|
17
22
|
Requires-Dist: aiofiles~=25.1.0
|
|
18
23
|
Provides-Extra: test
|
|
19
24
|
Requires-Dist: pytest; extra == "test"
|
|
@@ -21,13 +26,18 @@ Requires-Dist: pytest-asyncio; extra == "test"
|
|
|
21
26
|
Requires-Dist: aioresponses; extra == "test"
|
|
22
27
|
Requires-Dist: pytest-mock; extra == "test"
|
|
23
28
|
Requires-Dist: pydantic; extra == "test"
|
|
29
|
+
Requires-Dist: types-aiofiles; extra == "test"
|
|
24
30
|
Provides-Extra: pydantic
|
|
25
31
|
Requires-Dist: pydantic; extra == "pydantic"
|
|
26
32
|
Dynamic: license-file
|
|
27
33
|
|
|
28
34
|
# Avtomatika Worker SDK
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
[](https://opensource.org/licenses/MIT)
|
|
37
|
+
[](https://www.python.org/downloads/release/python-3110/)
|
|
38
|
+
[](https://github.com/astral-sh/ruff)
|
|
39
|
+
|
|
40
|
+
This is the official SDK for creating workers compatible with the **[Avtomatika Orchestrator](https://github.com/avtomatika-ai/avtomatika)**. It is built upon the **[Avtomatika Protocol](https://github.com/avtomatika-ai/rxon)** and implements the **[HLN Protocol](https://github.com/avtomatika-ai/hln)**, handling all communication complexity (polling, heartbeats, S3 offloading) so you can focus on writing your business logic.
|
|
31
41
|
|
|
32
42
|
## Installation
|
|
33
43
|
|
|
@@ -285,7 +295,7 @@ async def image_resizer(params: ResizeParams, **kwargs):
|
|
|
285
295
|
|
|
286
296
|
### 1. Task Handlers
|
|
287
297
|
|
|
288
|
-
Each handler is
|
|
298
|
+
Each handler is a function (either `async def` or `def`) that accepts two arguments:
|
|
289
299
|
|
|
290
300
|
- `params` (`dict`, `dataclass`, or `pydantic.BaseModel`): The parameters for the task, automatically validated and instantiated based on your type hint.
|
|
291
301
|
- `**kwargs`: Additional metadata about the task, including:
|
|
@@ -293,6 +303,18 @@ Each handler is an asynchronous function that accepts two arguments:
|
|
|
293
303
|
- `job_id` (`str`): The ID of the parent `Job` to which the task belongs.
|
|
294
304
|
- `priority` (`int`): The execution priority of the task.
|
|
295
305
|
|
|
306
|
+
**Synchronous Handlers:**
|
|
307
|
+
If you define your handler as a standard synchronous function (`def handler(...)`), the SDK will automatically execute it in a separate thread using `asyncio.to_thread`. This ensures that CPU-intensive operations (like model inference) do not block the worker's main event loop, allowing heartbeats and other background tasks to continue running smoothly.
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
@worker.task("cpu_heavy_task")
|
|
311
|
+
def heavy_computation(params: dict, **kwargs):
|
|
312
|
+
# This will run in a thread, not blocking the loop
|
|
313
|
+
import time
|
|
314
|
+
time.sleep(10)
|
|
315
|
+
return {"status": "success"}
|
|
316
|
+
```
|
|
317
|
+
|
|
296
318
|
### 2. Concurrency Limiting
|
|
297
319
|
|
|
298
320
|
The worker allows you to control how many tasks are executed in parallel. This can be configured at two levels:
|
|
@@ -472,7 +494,7 @@ async def generate_report(params: dict, files: TaskFiles, **kwargs):
|
|
|
472
494
|
|
|
473
495
|
### 6. Handling Large Files (S3 Payload Offloading)
|
|
474
496
|
|
|
475
|
-
The SDK supports working with large files "out of the box" via S3-compatible storage.
|
|
497
|
+
The SDK supports working with large files "out of the box" via S3-compatible storage, using the high-performance **`obstore`** library (Rust-based).
|
|
476
498
|
|
|
477
499
|
- **Automatic Download**: If a value in `params` is a URI of the form `s3://...`, the SDK will automatically download the file to the local disk and replace the URI in `params` with the local path. **If the URI ends with `/` (e.g., `s3://bucket/data/`), the SDK treats it as a folder prefix and recursively downloads all matching objects into a local directory.**
|
|
478
500
|
- **Automatic Upload**: If your handler returns a local file path in `data` (located within the `TASK_FILES_DIR` directory), the SDK will automatically upload this file to S3 and replace the path with an `s3://` URI in the final result. **If the path is a directory, the SDK recursively uploads all files within it.**
|
|
@@ -520,6 +542,48 @@ This only requires configuring environment variables for S3 access (see Full Con
|
|
|
520
542
|
|
|
521
543
|
### 7. WebSocket Support
|
|
522
544
|
|
|
545
|
+
For real-time communication (e.g., immediate task cancellation), the worker supports WebSocket connections. This is enabled by setting `WORKER_ENABLE_WEBSOCKETS=true`. When connected, the orchestrator can push commands like `cancel_task` directly to the worker.
|
|
546
|
+
|
|
547
|
+
### 8. Middleware
|
|
548
|
+
|
|
549
|
+
The worker supports a middleware system, allowing you to wrap task executions with custom logic. This is particularly useful for resource management (e.g., acquiring GPU locks), logging, error handling, or **Dependency Injection**.
|
|
550
|
+
|
|
551
|
+
Middleware functions wrap the execution of the task handler (and any subsequent middlewares). They receive a context dictionary and the next handler in the chain.
|
|
552
|
+
|
|
553
|
+
The `context` dictionary contains:
|
|
554
|
+
- `task_id`, `job_id`, `task_name`: Metadata.
|
|
555
|
+
- `params`: The validated parameters object.
|
|
556
|
+
- `handler_kwargs`: A dictionary of arguments that will be passed to the handler. **Middleware can modify this dictionary to inject dependencies.**
|
|
557
|
+
|
|
558
|
+
**Example: GPU Resource Manager & Dependency Injection**
|
|
559
|
+
|
|
560
|
+
```python
|
|
561
|
+
async def gpu_lock_middleware(context: dict, next_handler: callable):
|
|
562
|
+
# Pre-processing: Acquire resource
|
|
563
|
+
print(f"Acquiring GPU for task {context['task_id']}...")
|
|
564
|
+
model_path = await resource_manager.allocate()
|
|
565
|
+
|
|
566
|
+
# Inject the model path into the handler's arguments
|
|
567
|
+
context["handler_kwargs"]["model_path"] = model_path
|
|
568
|
+
|
|
569
|
+
try:
|
|
570
|
+
# Execute the next handler in the chain
|
|
571
|
+
result = await next_handler()
|
|
572
|
+
return result
|
|
573
|
+
finally:
|
|
574
|
+
# Post-processing: Release resource
|
|
575
|
+
print(f"Releasing GPU for task {context['task_id']}...")
|
|
576
|
+
resource_manager.release()
|
|
577
|
+
|
|
578
|
+
# Register the middleware
|
|
579
|
+
worker.add_middleware(gpu_lock_middleware)
|
|
580
|
+
|
|
581
|
+
# Handler now receives 'model_path' automatically
|
|
582
|
+
@worker.task("generate")
|
|
583
|
+
def generate(params, model_path, **kwargs):
|
|
584
|
+
print(f"Using model at: {model_path}")
|
|
585
|
+
```
|
|
586
|
+
|
|
523
587
|
## Advanced Features
|
|
524
588
|
|
|
525
589
|
### Reporting Skill & Model Dependencies
|
|
@@ -576,8 +640,11 @@ The worker is fully configured via environment variables.
|
|
|
576
640
|
| `WORKER_TYPE` | A string identifying the type of the worker. | `generic-cpu-worker` |
|
|
577
641
|
| `WORKER_PORT` | The port for the worker's health check server. | `8083` |
|
|
578
642
|
| `WORKER_TOKEN` | A common authentication token used to connect to orchestrators. | `your-secret-worker-token` |
|
|
579
|
-
|
|
580
|
-
|
|
643
|
+
- **`WORKER_INDIVIDUAL_TOKEN`**: An individual token for this worker, which overrides `WORKER_TOKEN` if set.
|
|
644
|
+
- **`TLS_CA_PATH`**: Path to the CA certificate to verify the orchestrator.
|
|
645
|
+
- **`TLS_CERT_PATH`**: Path to the client certificate for mTLS.
|
|
646
|
+
- **`TLS_KEY_PATH`**: Path to the client private key for mTLS.
|
|
647
|
+
- **`ORCHESTRATOR_URL`**: The address of the Avtomatika orchestrator.
|
|
581
648
|
| `ORCHESTRATORS_CONFIG` | A JSON string with a list of orchestrators for multi-orchestrator modes. | `[]` |
|
|
582
649
|
| `MULTI_ORCHESTRATOR_MODE` | The mode for handling multiple orchestrators. Possible values: `FAILOVER`, `ROUND_ROBIN`. | `FAILOVER` |
|
|
583
650
|
| `MAX_CONCURRENT_TASKS` | The maximum number of tasks the worker can execute simultaneously. | `10` |
|
|
@@ -600,11 +667,13 @@ The worker is fully configured via environment variables.
|
|
|
600
667
|
| `S3_ACCESS_KEY` | The access key for S3. | - |
|
|
601
668
|
| `S3_SECRET_KEY` | The secret key for S3. | - |
|
|
602
669
|
| `S3_DEFAULT_BUCKET` | The default bucket name for uploading results. | `avtomatika-payloads` |
|
|
670
|
+
| `S3_REGION` | The region for S3 storage (required by some providers). | `us-east-1` |
|
|
603
671
|
|
|
604
672
|
## Development
|
|
605
673
|
|
|
606
|
-
To install the necessary dependencies for running tests
|
|
674
|
+
To install the necessary dependencies for running tests (assuming you are in the package root):
|
|
607
675
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
676
|
+
1. Install the worker in editable mode with test dependencies:
|
|
677
|
+
```bash
|
|
678
|
+
pip install -e .[test]
|
|
679
|
+
```
|
avtomatika_worker-1.0b2/src/avtomatika_worker.egg-info/PKG-INFO → avtomatika_worker-1.0b4/README.md
RENAMED
|
@@ -1,33 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: avtomatika-worker
|
|
3
|
-
Version: 1.0b2
|
|
4
|
-
Summary: Worker SDK for the Avtomatika orchestrator.
|
|
5
|
-
Project-URL: Homepage, https://github.com/avtomatika-ai/avtomatika-worker
|
|
6
|
-
Project-URL: Bug Tracker, https://github.com/avtomatika-ai/avtomatika-worker/issues
|
|
7
|
-
Classifier: Development Status :: 4 - Beta
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.11
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
License-File: LICENSE
|
|
14
|
-
Requires-Dist: aiohttp~=3.13.2
|
|
15
|
-
Requires-Dist: python-json-logger~=4.0.0
|
|
16
|
-
Requires-Dist: aioboto3~=15.5.0
|
|
17
|
-
Requires-Dist: aiofiles~=25.1.0
|
|
18
|
-
Provides-Extra: test
|
|
19
|
-
Requires-Dist: pytest; extra == "test"
|
|
20
|
-
Requires-Dist: pytest-asyncio; extra == "test"
|
|
21
|
-
Requires-Dist: aioresponses; extra == "test"
|
|
22
|
-
Requires-Dist: pytest-mock; extra == "test"
|
|
23
|
-
Requires-Dist: pydantic; extra == "test"
|
|
24
|
-
Provides-Extra: pydantic
|
|
25
|
-
Requires-Dist: pydantic; extra == "pydantic"
|
|
26
|
-
Dynamic: license-file
|
|
27
|
-
|
|
28
1
|
# Avtomatika Worker SDK
|
|
29
2
|
|
|
30
|
-
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.python.org/downloads/release/python-3110/)
|
|
5
|
+
[](https://github.com/astral-sh/ruff)
|
|
6
|
+
|
|
7
|
+
This is the official SDK for creating workers compatible with the **[Avtomatika Orchestrator](https://github.com/avtomatika-ai/avtomatika)**. It is built upon the **[Avtomatika Protocol](https://github.com/avtomatika-ai/rxon)** and implements the **[HLN Protocol](https://github.com/avtomatika-ai/hln)**, handling all communication complexity (polling, heartbeats, S3 offloading) so you can focus on writing your business logic.
|
|
31
8
|
|
|
32
9
|
## Installation
|
|
33
10
|
|
|
@@ -285,7 +262,7 @@ async def image_resizer(params: ResizeParams, **kwargs):
|
|
|
285
262
|
|
|
286
263
|
### 1. Task Handlers
|
|
287
264
|
|
|
288
|
-
Each handler is
|
|
265
|
+
Each handler is a function (either `async def` or `def`) that accepts two arguments:
|
|
289
266
|
|
|
290
267
|
- `params` (`dict`, `dataclass`, or `pydantic.BaseModel`): The parameters for the task, automatically validated and instantiated based on your type hint.
|
|
291
268
|
- `**kwargs`: Additional metadata about the task, including:
|
|
@@ -293,6 +270,18 @@ Each handler is an asynchronous function that accepts two arguments:
|
|
|
293
270
|
- `job_id` (`str`): The ID of the parent `Job` to which the task belongs.
|
|
294
271
|
- `priority` (`int`): The execution priority of the task.
|
|
295
272
|
|
|
273
|
+
**Synchronous Handlers:**
|
|
274
|
+
If you define your handler as a standard synchronous function (`def handler(...)`), the SDK will automatically execute it in a separate thread using `asyncio.to_thread`. This ensures that CPU-intensive operations (like model inference) do not block the worker's main event loop, allowing heartbeats and other background tasks to continue running smoothly.
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
@worker.task("cpu_heavy_task")
|
|
278
|
+
def heavy_computation(params: dict, **kwargs):
|
|
279
|
+
# This will run in a thread, not blocking the loop
|
|
280
|
+
import time
|
|
281
|
+
time.sleep(10)
|
|
282
|
+
return {"status": "success"}
|
|
283
|
+
```
|
|
284
|
+
|
|
296
285
|
### 2. Concurrency Limiting
|
|
297
286
|
|
|
298
287
|
The worker allows you to control how many tasks are executed in parallel. This can be configured at two levels:
|
|
@@ -472,7 +461,7 @@ async def generate_report(params: dict, files: TaskFiles, **kwargs):
|
|
|
472
461
|
|
|
473
462
|
### 6. Handling Large Files (S3 Payload Offloading)
|
|
474
463
|
|
|
475
|
-
The SDK supports working with large files "out of the box" via S3-compatible storage.
|
|
464
|
+
The SDK supports working with large files "out of the box" via S3-compatible storage, using the high-performance **`obstore`** library (Rust-based).
|
|
476
465
|
|
|
477
466
|
- **Automatic Download**: If a value in `params` is a URI of the form `s3://...`, the SDK will automatically download the file to the local disk and replace the URI in `params` with the local path. **If the URI ends with `/` (e.g., `s3://bucket/data/`), the SDK treats it as a folder prefix and recursively downloads all matching objects into a local directory.**
|
|
478
467
|
- **Automatic Upload**: If your handler returns a local file path in `data` (located within the `TASK_FILES_DIR` directory), the SDK will automatically upload this file to S3 and replace the path with an `s3://` URI in the final result. **If the path is a directory, the SDK recursively uploads all files within it.**
|
|
@@ -520,6 +509,48 @@ This only requires configuring environment variables for S3 access (see Full Con
|
|
|
520
509
|
|
|
521
510
|
### 7. WebSocket Support
|
|
522
511
|
|
|
512
|
+
For real-time communication (e.g., immediate task cancellation), the worker supports WebSocket connections. This is enabled by setting `WORKER_ENABLE_WEBSOCKETS=true`. When connected, the orchestrator can push commands like `cancel_task` directly to the worker.
|
|
513
|
+
|
|
514
|
+
### 8. Middleware
|
|
515
|
+
|
|
516
|
+
The worker supports a middleware system, allowing you to wrap task executions with custom logic. This is particularly useful for resource management (e.g., acquiring GPU locks), logging, error handling, or **Dependency Injection**.
|
|
517
|
+
|
|
518
|
+
Middleware functions wrap the execution of the task handler (and any subsequent middlewares). They receive a context dictionary and the next handler in the chain.
|
|
519
|
+
|
|
520
|
+
The `context` dictionary contains:
|
|
521
|
+
- `task_id`, `job_id`, `task_name`: Metadata.
|
|
522
|
+
- `params`: The validated parameters object.
|
|
523
|
+
- `handler_kwargs`: A dictionary of arguments that will be passed to the handler. **Middleware can modify this dictionary to inject dependencies.**
|
|
524
|
+
|
|
525
|
+
**Example: GPU Resource Manager & Dependency Injection**
|
|
526
|
+
|
|
527
|
+
```python
|
|
528
|
+
async def gpu_lock_middleware(context: dict, next_handler: callable):
|
|
529
|
+
# Pre-processing: Acquire resource
|
|
530
|
+
print(f"Acquiring GPU for task {context['task_id']}...")
|
|
531
|
+
model_path = await resource_manager.allocate()
|
|
532
|
+
|
|
533
|
+
# Inject the model path into the handler's arguments
|
|
534
|
+
context["handler_kwargs"]["model_path"] = model_path
|
|
535
|
+
|
|
536
|
+
try:
|
|
537
|
+
# Execute the next handler in the chain
|
|
538
|
+
result = await next_handler()
|
|
539
|
+
return result
|
|
540
|
+
finally:
|
|
541
|
+
# Post-processing: Release resource
|
|
542
|
+
print(f"Releasing GPU for task {context['task_id']}...")
|
|
543
|
+
resource_manager.release()
|
|
544
|
+
|
|
545
|
+
# Register the middleware
|
|
546
|
+
worker.add_middleware(gpu_lock_middleware)
|
|
547
|
+
|
|
548
|
+
# Handler now receives 'model_path' automatically
|
|
549
|
+
@worker.task("generate")
|
|
550
|
+
def generate(params, model_path, **kwargs):
|
|
551
|
+
print(f"Using model at: {model_path}")
|
|
552
|
+
```
|
|
553
|
+
|
|
523
554
|
## Advanced Features
|
|
524
555
|
|
|
525
556
|
### Reporting Skill & Model Dependencies
|
|
@@ -576,8 +607,11 @@ The worker is fully configured via environment variables.
|
|
|
576
607
|
| `WORKER_TYPE` | A string identifying the type of the worker. | `generic-cpu-worker` |
|
|
577
608
|
| `WORKER_PORT` | The port for the worker's health check server. | `8083` |
|
|
578
609
|
| `WORKER_TOKEN` | A common authentication token used to connect to orchestrators. | `your-secret-worker-token` |
|
|
579
|
-
|
|
580
|
-
|
|
610
|
+
- **`WORKER_INDIVIDUAL_TOKEN`**: An individual token for this worker, which overrides `WORKER_TOKEN` if set.
|
|
611
|
+
- **`TLS_CA_PATH`**: Path to the CA certificate to verify the orchestrator.
|
|
612
|
+
- **`TLS_CERT_PATH`**: Path to the client certificate for mTLS.
|
|
613
|
+
- **`TLS_KEY_PATH`**: Path to the client private key for mTLS.
|
|
614
|
+
- **`ORCHESTRATOR_URL`**: The address of the Avtomatika orchestrator.
|
|
581
615
|
| `ORCHESTRATORS_CONFIG` | A JSON string with a list of orchestrators for multi-orchestrator modes. | `[]` |
|
|
582
616
|
| `MULTI_ORCHESTRATOR_MODE` | The mode for handling multiple orchestrators. Possible values: `FAILOVER`, `ROUND_ROBIN`. | `FAILOVER` |
|
|
583
617
|
| `MAX_CONCURRENT_TASKS` | The maximum number of tasks the worker can execute simultaneously. | `10` |
|
|
@@ -600,11 +634,13 @@ The worker is fully configured via environment variables.
|
|
|
600
634
|
| `S3_ACCESS_KEY` | The access key for S3. | - |
|
|
601
635
|
| `S3_SECRET_KEY` | The secret key for S3. | - |
|
|
602
636
|
| `S3_DEFAULT_BUCKET` | The default bucket name for uploading results. | `avtomatika-payloads` |
|
|
637
|
+
| `S3_REGION` | The region for S3 storage (required by some providers). | `us-east-1` |
|
|
603
638
|
|
|
604
639
|
## Development
|
|
605
640
|
|
|
606
|
-
To install the necessary dependencies for running tests
|
|
641
|
+
To install the necessary dependencies for running tests (assuming you are in the package root):
|
|
607
642
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
643
|
+
1. Install the worker in editable mode with test dependencies:
|
|
644
|
+
```bash
|
|
645
|
+
pip install -e .[test]
|
|
646
|
+
```
|
|
@@ -4,20 +4,27 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "avtomatika-worker"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.0b4"
|
|
8
8
|
description = "Worker SDK for the Avtomatika orchestrator."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "Dmitrii Gagarin", email = "madgagarin@gmail.com"},
|
|
13
|
+
]
|
|
14
|
+
keywords = ["worker", "sdk", "orchestrator", "distributed", "task-queue", "rxon", "hln"]
|
|
11
15
|
classifiers = [
|
|
12
16
|
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
13
18
|
"Programming Language :: Python :: 3",
|
|
14
19
|
"License :: OSI Approved :: MIT License",
|
|
15
20
|
"Operating System :: OS Independent",
|
|
21
|
+
"Typing :: Typed",
|
|
16
22
|
]
|
|
17
23
|
dependencies = [
|
|
24
|
+
"rxon==1.0b2",
|
|
18
25
|
"aiohttp~=3.13.2",
|
|
19
26
|
"python-json-logger~=4.0.0",
|
|
20
|
-
"
|
|
27
|
+
"obstore>=0.1",
|
|
21
28
|
"aiofiles~=25.1.0",
|
|
22
29
|
]
|
|
23
30
|
|
|
@@ -28,6 +35,7 @@ test = [
|
|
|
28
35
|
"aioresponses",
|
|
29
36
|
"pytest-mock",
|
|
30
37
|
"pydantic",
|
|
38
|
+
"types-aiofiles",
|
|
31
39
|
]
|
|
32
40
|
pydantic = ["pydantic"]
|
|
33
41
|
|
|
@@ -38,6 +46,9 @@ pydantic = ["pydantic"]
|
|
|
38
46
|
[tool.setuptools.packages.find]
|
|
39
47
|
where = ["src"]
|
|
40
48
|
|
|
49
|
+
[tool.setuptools.package-data]
|
|
50
|
+
"avtomatika_worker" = ["py.typed"]
|
|
51
|
+
|
|
41
52
|
[tool.pytest.ini_options]
|
|
42
53
|
markers = [
|
|
43
54
|
"e2e: marks tests as end-to-end tests",
|
|
@@ -4,13 +4,15 @@ from os import getenv
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
from uuid import uuid4
|
|
6
6
|
|
|
7
|
+
from rxon.validators import validate_identifier
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
class WorkerConfig:
|
|
9
11
|
"""A class for centralized management of worker configuration.
|
|
10
12
|
Reads parameters from environment variables and provides default values.
|
|
11
13
|
"""
|
|
12
14
|
|
|
13
|
-
def __init__(self):
|
|
15
|
+
def __init__(self) -> None:
|
|
14
16
|
# --- Basic worker information ---
|
|
15
17
|
self.WORKER_ID: str = getenv("WORKER_ID", f"worker-{uuid4()}")
|
|
16
18
|
self.WORKER_TYPE: str = getenv("WORKER_TYPE", "generic-cpu-worker")
|
|
@@ -29,6 +31,9 @@ class WorkerConfig:
|
|
|
29
31
|
"WORKER_INDIVIDUAL_TOKEN",
|
|
30
32
|
getenv("WORKER_TOKEN", "your-secret-worker-token"),
|
|
31
33
|
)
|
|
34
|
+
self.TLS_CA_PATH: str | None = getenv("TLS_CA_PATH")
|
|
35
|
+
self.TLS_CERT_PATH: str | None = getenv("TLS_CERT_PATH")
|
|
36
|
+
self.TLS_KEY_PATH: str | None = getenv("TLS_KEY_PATH")
|
|
32
37
|
|
|
33
38
|
# --- Resources and performance ---
|
|
34
39
|
self.COST_PER_SKILL: dict[str, float] = self._load_json_from_env("COST_PER_SKILL", default={})
|
|
@@ -54,6 +59,7 @@ class WorkerConfig:
|
|
|
54
59
|
self.S3_ACCESS_KEY: str | None = getenv("S3_ACCESS_KEY")
|
|
55
60
|
self.S3_SECRET_KEY: str | None = getenv("S3_SECRET_KEY")
|
|
56
61
|
self.S3_DEFAULT_BUCKET: str = getenv("S3_DEFAULT_BUCKET", "avtomatika-payloads")
|
|
62
|
+
self.S3_REGION: str = getenv("S3_REGION", "us-east-1")
|
|
57
63
|
|
|
58
64
|
# --- Tuning parameters ---
|
|
59
65
|
self.HEARTBEAT_INTERVAL: float = float(getenv("HEARTBEAT_INTERVAL", "15"))
|
|
@@ -70,6 +76,19 @@ class WorkerConfig:
|
|
|
70
76
|
self.ENABLE_WEBSOCKETS: bool = getenv("WORKER_ENABLE_WEBSOCKETS", "false").lower() == "true"
|
|
71
77
|
self.MULTI_ORCHESTRATOR_MODE: str = getenv("MULTI_ORCHESTRATOR_MODE", "FAILOVER")
|
|
72
78
|
|
|
79
|
+
def validate(self) -> None:
|
|
80
|
+
"""Validates critical configuration parameters."""
|
|
81
|
+
validate_identifier(self.WORKER_ID, "WORKER_ID")
|
|
82
|
+
if self.WORKER_TOKEN == "your-secret-worker-token":
|
|
83
|
+
print("Warning: WORKER_TOKEN is set to the default value. Tasks might fail authentication.")
|
|
84
|
+
|
|
85
|
+
if not self.ORCHESTRATORS:
|
|
86
|
+
raise ValueError("No orchestrators configured.")
|
|
87
|
+
|
|
88
|
+
for o in self.ORCHESTRATORS:
|
|
89
|
+
if not o.get("url"):
|
|
90
|
+
raise ValueError("Orchestrator configuration missing URL.")
|
|
91
|
+
|
|
73
92
|
def _get_orchestrators_config(self) -> list[dict[str, Any]]:
|
|
74
93
|
"""
|
|
75
94
|
Loads orchestrator configuration from the ORCHESTRATORS_CONFIG environment variable.
|
|
File without changes
|