avtomatika 1.0b7__py3-none-any.whl → 1.0b8__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.
- avtomatika/app_keys.py +1 -0
- avtomatika/config.py +10 -0
- avtomatika/data_types.py +2 -1
- avtomatika/dispatcher.py +8 -26
- avtomatika/engine.py +19 -1
- avtomatika/executor.py +34 -6
- avtomatika/health_checker.py +23 -5
- avtomatika/history/base.py +60 -6
- avtomatika/history/noop.py +18 -7
- avtomatika/history/postgres.py +8 -6
- avtomatika/history/sqlite.py +7 -5
- avtomatika/metrics.py +1 -1
- avtomatika/reputation.py +46 -40
- avtomatika/s3.py +323 -0
- avtomatika/storage/base.py +45 -4
- avtomatika/storage/memory.py +44 -6
- avtomatika/storage/redis.py +185 -252
- avtomatika/utils/webhook_sender.py +44 -2
- avtomatika/watcher.py +33 -35
- avtomatika/ws_manager.py +7 -6
- {avtomatika-1.0b7.dist-info → avtomatika-1.0b8.dist-info}/METADATA +50 -2
- avtomatika-1.0b8.dist-info/RECORD +46 -0
- avtomatika-1.0b7.dist-info/RECORD +0 -45
- {avtomatika-1.0b7.dist-info → avtomatika-1.0b8.dist-info}/WHEEL +0 -0
- {avtomatika-1.0b7.dist-info → avtomatika-1.0b8.dist-info}/licenses/LICENSE +0 -0
- {avtomatika-1.0b7.dist-info → avtomatika-1.0b8.dist-info}/top_level.txt +0 -0
avtomatika/watcher.py
CHANGED
|
@@ -26,46 +26,43 @@ class Watcher:
|
|
|
26
26
|
self._running = True
|
|
27
27
|
while self._running:
|
|
28
28
|
try:
|
|
29
|
-
await sleep(self.watch_interval_seconds)
|
|
30
|
-
|
|
31
29
|
# Attempt to acquire distributed lock
|
|
32
30
|
# We set TTL slightly longer than the expected execution time (60s)
|
|
33
|
-
if
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
if await self.storage.acquire_lock("global_watcher_lock", self._instance_id, 60):
|
|
32
|
+
try:
|
|
33
|
+
logger.debug("Watcher running check for timed out jobs...")
|
|
34
|
+
timed_out_job_ids = await self.storage.get_timed_out_jobs(limit=100)
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
for job_id in timed_out_job_ids:
|
|
37
|
+
logger.warning(f"Job {job_id} timed out. Moving to failed state.")
|
|
38
|
+
try:
|
|
39
|
+
# Get the latest version to avoid overwriting
|
|
40
|
+
job_state = await self.storage.get_job_state(job_id)
|
|
41
|
+
if job_state and job_state["status"] == "waiting_for_worker":
|
|
42
|
+
job_state["status"] = "failed"
|
|
43
|
+
job_state["error_message"] = "Worker task timed out."
|
|
44
|
+
await self.storage.save_job_state(job_id, job_state)
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
try:
|
|
44
|
-
# Get the latest version to avoid overwriting
|
|
45
|
-
job_state = await self.storage.get_job_state(job_id)
|
|
46
|
-
if job_state and job_state["status"] == "waiting_for_worker":
|
|
47
|
-
job_state["status"] = "failed"
|
|
48
|
-
job_state["error_message"] = "Worker task timed out."
|
|
49
|
-
await self.storage.save_job_state(job_id, job_state)
|
|
46
|
+
# Increment the metric
|
|
47
|
+
from . import metrics
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
49
|
+
metrics.jobs_failed_total.inc(
|
|
50
|
+
{
|
|
51
|
+
metrics.LABEL_BLUEPRINT: job_state.get(
|
|
52
|
+
"blueprint_name",
|
|
53
|
+
"unknown",
|
|
54
|
+
),
|
|
55
|
+
},
|
|
56
|
+
)
|
|
57
|
+
except Exception:
|
|
58
|
+
logger.exception(
|
|
59
|
+
f"Failed to update state for timed out job {job_id}",
|
|
61
60
|
)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
# Always release the lock so we (or others) can run next time
|
|
68
|
-
await self.storage.release_lock("global_watcher_lock", self._instance_id)
|
|
61
|
+
finally:
|
|
62
|
+
# Always release the lock so we (or others) can run next time
|
|
63
|
+
await self.storage.release_lock("global_watcher_lock", self._instance_id)
|
|
64
|
+
else:
|
|
65
|
+
logger.debug("Watcher lock held by another instance. Skipping check.")
|
|
69
66
|
|
|
70
67
|
except CancelledError:
|
|
71
68
|
logger.info("Watcher received cancellation request.")
|
|
@@ -73,7 +70,8 @@ class Watcher:
|
|
|
73
70
|
except Exception:
|
|
74
71
|
logger.exception("Error in Watcher main loop.")
|
|
75
72
|
|
|
76
|
-
|
|
73
|
+
# Sleep at the end of iteration
|
|
74
|
+
await sleep(self.watch_interval_seconds)
|
|
77
75
|
|
|
78
76
|
def stop(self):
|
|
79
77
|
"""Stops the watcher."""
|
avtomatika/ws_manager.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from asyncio import Lock
|
|
2
2
|
from logging import getLogger
|
|
3
|
+
from typing import Any
|
|
3
4
|
|
|
4
5
|
from aiohttp import web
|
|
5
6
|
|
|
@@ -9,11 +10,11 @@ logger = getLogger(__name__)
|
|
|
9
10
|
class WebSocketManager:
|
|
10
11
|
"""Manages active WebSocket connections from workers."""
|
|
11
12
|
|
|
12
|
-
def __init__(self):
|
|
13
|
+
def __init__(self) -> None:
|
|
13
14
|
self._connections: dict[str, web.WebSocketResponse] = {}
|
|
14
15
|
self._lock = Lock()
|
|
15
16
|
|
|
16
|
-
async def register(self, worker_id: str, ws: web.WebSocketResponse):
|
|
17
|
+
async def register(self, worker_id: str, ws: web.WebSocketResponse) -> None:
|
|
17
18
|
"""Registers a new WebSocket connection for a worker."""
|
|
18
19
|
async with self._lock:
|
|
19
20
|
if worker_id in self._connections:
|
|
@@ -22,14 +23,14 @@ class WebSocketManager:
|
|
|
22
23
|
self._connections[worker_id] = ws
|
|
23
24
|
logger.info(f"WebSocket connection registered for worker {worker_id}.")
|
|
24
25
|
|
|
25
|
-
async def unregister(self, worker_id: str):
|
|
26
|
+
async def unregister(self, worker_id: str) -> None:
|
|
26
27
|
"""Unregisters a WebSocket connection."""
|
|
27
28
|
async with self._lock:
|
|
28
29
|
if worker_id in self._connections:
|
|
29
30
|
del self._connections[worker_id]
|
|
30
31
|
logger.info(f"WebSocket connection for worker {worker_id} unregistered.")
|
|
31
32
|
|
|
32
|
-
async def send_command(self, worker_id: str, command: dict):
|
|
33
|
+
async def send_command(self, worker_id: str, command: dict[str, Any]) -> bool:
|
|
33
34
|
"""Sends a JSON command to a specific worker."""
|
|
34
35
|
async with self._lock:
|
|
35
36
|
connection = self._connections.get(worker_id)
|
|
@@ -46,7 +47,7 @@ class WebSocketManager:
|
|
|
46
47
|
return False
|
|
47
48
|
|
|
48
49
|
@staticmethod
|
|
49
|
-
async def handle_message(worker_id: str, message: dict):
|
|
50
|
+
async def handle_message(worker_id: str, message: dict[str, Any]) -> None:
|
|
50
51
|
"""Handles an incoming message from a worker."""
|
|
51
52
|
event_type = message.get("event")
|
|
52
53
|
if event_type == "progress_update":
|
|
@@ -59,7 +60,7 @@ class WebSocketManager:
|
|
|
59
60
|
else:
|
|
60
61
|
logger.debug(f"Received unhandled event from worker {worker_id}: {event_type}")
|
|
61
62
|
|
|
62
|
-
async def close_all(self):
|
|
63
|
+
async def close_all(self) -> None:
|
|
63
64
|
"""Closes all active WebSocket connections."""
|
|
64
65
|
async with self._lock:
|
|
65
66
|
logger.info(f"Closing {len(self._connections)} active WebSocket connections...")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: avtomatika
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.0b8
|
|
4
4
|
Summary: A state-machine based orchestrator for long-running AI and other jobs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/avtomatika-ai/avtomatika
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/avtomatika-ai/avtomatika/issues
|
|
@@ -20,6 +20,9 @@ Requires-Dist: msgpack~=1.1
|
|
|
20
20
|
Requires-Dist: orjson~=3.11
|
|
21
21
|
Provides-Extra: redis
|
|
22
22
|
Requires-Dist: redis~=7.1; extra == "redis"
|
|
23
|
+
Provides-Extra: s3
|
|
24
|
+
Requires-Dist: obstore>=0.2; extra == "s3"
|
|
25
|
+
Requires-Dist: aiofiles~=23.2; extra == "s3"
|
|
23
26
|
Provides-Extra: history
|
|
24
27
|
Requires-Dist: aiosqlite~=0.22; extra == "history"
|
|
25
28
|
Requires-Dist: asyncpg~=0.30; extra == "history"
|
|
@@ -37,10 +40,13 @@ Requires-Dist: pytest-mock~=3.14; extra == "test"
|
|
|
37
40
|
Requires-Dist: aioresponses~=0.7; extra == "test"
|
|
38
41
|
Requires-Dist: backports.zstd~=1.2; extra == "test"
|
|
39
42
|
Requires-Dist: opentelemetry-instrumentation-aiohttp-client; extra == "test"
|
|
43
|
+
Requires-Dist: obstore>=0.2; extra == "test"
|
|
44
|
+
Requires-Dist: aiofiles~=23.2; extra == "test"
|
|
40
45
|
Provides-Extra: all
|
|
41
46
|
Requires-Dist: avtomatika[redis]; extra == "all"
|
|
42
47
|
Requires-Dist: avtomatika[history]; extra == "all"
|
|
43
48
|
Requires-Dist: avtomatika[telemetry]; extra == "all"
|
|
49
|
+
Requires-Dist: avtomatika[s3]; extra == "all"
|
|
44
50
|
Dynamic: license-file
|
|
45
51
|
|
|
46
52
|
# Avtomatika Orchestrator
|
|
@@ -60,6 +66,7 @@ This document serves as a comprehensive guide for developers looking to build pi
|
|
|
60
66
|
- [Parallel Execution and Aggregation (Fan-out/Fan-in)](#parallel-execution-and-aggregation-fan-outfan-in)
|
|
61
67
|
- [Dependency Injection (DataStore)](#dependency-injection-datastore)
|
|
62
68
|
- [Native Scheduler](#native-scheduler)
|
|
69
|
+
- [S3 Payload Offloading](#s3-payload-offloading)
|
|
63
70
|
- [Webhook Notifications](#webhook-notifications)
|
|
64
71
|
- [Production Configuration](#production-configuration)
|
|
65
72
|
- [Fault Tolerance](#fault-tolerance)
|
|
@@ -107,6 +114,11 @@ Avtomatika is part of a larger ecosystem:
|
|
|
107
114
|
pip install "avtomatika[telemetry]"
|
|
108
115
|
```
|
|
109
116
|
|
|
117
|
+
* **Install with S3 support (Payload Offloading):**
|
|
118
|
+
```bash
|
|
119
|
+
pip install "avtomatika[s3]"
|
|
120
|
+
```
|
|
121
|
+
|
|
110
122
|
* **Install all dependencies, including for testing:**
|
|
111
123
|
```bash
|
|
112
124
|
pip install "avtomatika[all,test]"
|
|
@@ -250,6 +262,19 @@ async def publish_handler_old_style(context):
|
|
|
250
262
|
print(f"Job {context.job_id}: Publishing video at {output_path} ({duration}s).")
|
|
251
263
|
context.actions.transition_to("complete")
|
|
252
264
|
```
|
|
265
|
+
## Key Concepts: JobContext and Actions
|
|
266
|
+
|
|
267
|
+
### High Performance Architecture
|
|
268
|
+
|
|
269
|
+
Avtomatika is engineered for high-load environments with thousands of concurrent workers.
|
|
270
|
+
|
|
271
|
+
* **O(1) Dispatcher**: Uses advanced Redis Set intersections to find suitable workers instantly, regardless of the cluster size. No O(N) scanning.
|
|
272
|
+
* **Non-Blocking I/O**:
|
|
273
|
+
* **Webhooks**: Sent via a bounded background queue to prevent backpressure.
|
|
274
|
+
* **History Logging**: Writes to SQL databases are buffered and asynchronous, ensuring the main execution loop never blocks.
|
|
275
|
+
* **Redis Streams**: Uses blocking reads to eliminate busy-waiting and reduce CPU usage.
|
|
276
|
+
* **Memory Safety**: S3 file transfers use streaming to handle multi-gigabyte files with constant, low RAM usage.
|
|
277
|
+
|
|
253
278
|
## Blueprint Cookbook: Key Features
|
|
254
279
|
|
|
255
280
|
### 1. Conditional Transitions (`.when()`)
|
|
@@ -365,7 +390,30 @@ daily_at = "02:00"
|
|
|
365
390
|
|
|
366
391
|
The orchestrator can send asynchronous notifications to an external system when a job completes, fails, or is quarantined. This eliminates the need for clients to constantly poll the API for status updates.
|
|
367
392
|
|
|
368
|
-
|
|
393
|
+
### 7. S3 Payload Offloading
|
|
394
|
+
|
|
395
|
+
Orchestrator provides first-class support for handling large files via S3-compatible storage, powered by the high-performance `obstore` library (Rust bindings).
|
|
396
|
+
|
|
397
|
+
* **Memory Safe (Streaming)**: Uses streaming for uploads and downloads, allowing processing of files larger than available RAM without OOM errors.
|
|
398
|
+
* **Managed Mode**: The Orchestrator manages file lifecycle (automatic cleanup of S3 objects and local temporary files on job completion).
|
|
399
|
+
* **Dependency Injection**: Use the `task_files` argument in your handlers to easily read/write data.
|
|
400
|
+
* **Directory Support**: Supports recursive download and upload of entire directories.
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
@bp.handler_for("process_data")
|
|
404
|
+
async def process_data(task_files, actions):
|
|
405
|
+
# Streaming download of a large file
|
|
406
|
+
local_path = await task_files.download("large_dataset.csv")
|
|
407
|
+
|
|
408
|
+
# ... process data ...
|
|
409
|
+
|
|
410
|
+
# Upload results
|
|
411
|
+
await task_files.write_json("results.json", {"status": "done"})
|
|
412
|
+
|
|
413
|
+
actions.transition_to("finished")
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Production Configuration
|
|
369
417
|
* **Events:**
|
|
370
418
|
* `job_finished`: The job reached a final success state.
|
|
371
419
|
* `job_failed`: The job failed (e.g., due to an error or invalid input).
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
avtomatika/__init__.py,sha256=D5r3L-H06uxsY_wgfh7u9YR29QvZMer1BlvzjW9Umfo,701
|
|
2
|
+
avtomatika/api.html,sha256=RLx-D1uFCSAXIf_2WgFlSTWrWPcmonNYM-9oNanKXBg,32835
|
|
3
|
+
avtomatika/app_keys.py,sha256=XL9Q1Ef5JYa_JG8LM3jzb3cOQjnKaM6ypwqXWnUKeDU,1212
|
|
4
|
+
avtomatika/blueprint.py,sha256=AJ8hZkzvqkdu9aPmlJeFzuSj57L6Xm41KS9kBMGB4Vg,11827
|
|
5
|
+
avtomatika/client_config_loader.py,sha256=zVVHZlxSqZUaNpZ4zoU0T1CFYXdxy-3vKSmPcaFuHSY,2772
|
|
6
|
+
avtomatika/compression.py,sha256=bhA1kw4YrCR3I3kdquZSY0fAzCrRrjtz55uepzLUDKI,2498
|
|
7
|
+
avtomatika/config.py,sha256=zqaZrt44Zd_ppvWPDkSth1nJydhAsK0jQLDo0QIW77A,3103
|
|
8
|
+
avtomatika/constants.py,sha256=WL58Nh-EY6baM9Ur_tR9merwPRGb41_klUG2V-yUUaA,963
|
|
9
|
+
avtomatika/context.py,sha256=T6Ux4Fb1DwWRGTpMNeukM51MQDQbGk2HS6Cwpc0dc1s,4248
|
|
10
|
+
avtomatika/data_types.py,sha256=nm9pLhLLx8fngjvAE8d3nQZkD8Y3Q28RHch9kjYAG2Y,1447
|
|
11
|
+
avtomatika/datastore.py,sha256=gJjhZ5kxjF8pmbbPQb_qu3HPUpfy2c6T75KZ-smb_zg,545
|
|
12
|
+
avtomatika/dispatcher.py,sha256=CKqniknJZe7gjY7QmGlODJc5X8B6qWjtr2UxRivUbuY,8603
|
|
13
|
+
avtomatika/engine.py,sha256=VUw5s65Q403a1JgkRtF1KeSiVx1W6MFmukxZpYN-f00,16175
|
|
14
|
+
avtomatika/executor.py,sha256=K7RGGxWz_4n6q0m8tW0oNtUJm90b-4O2U9lTB_yLX-k,24461
|
|
15
|
+
avtomatika/health_checker.py,sha256=jXYSH4BPeZ4LCxSZV4uXM4BZhGJYgpoAOWQXE8yojLo,2078
|
|
16
|
+
avtomatika/logging_config.py,sha256=Zb6f9Nri9WVWhlpuBg6Lpi5SWRLGIUmS8Dc3xD1Gg0g,2993
|
|
17
|
+
avtomatika/metrics.py,sha256=tiksK1fFSOMlz8zFu6GT19JTduvxMTNlLu0QFrTHoQI,1866
|
|
18
|
+
avtomatika/py.typed,sha256=CT_L7gw2MLcQY-X0vs-xB5Vr0wzvGo7GuQYPI_qwJE8,65
|
|
19
|
+
avtomatika/quota.py,sha256=DNcaL6k0J1REeP8sVqbY9FprY_3BSr2SxM2Vf4mEqdw,1612
|
|
20
|
+
avtomatika/ratelimit.py,sha256=hFGW5oN9G6_W_jnHmopXW8bRjjzlvanY19MLghsNLE8,1306
|
|
21
|
+
avtomatika/reputation.py,sha256=pK-x9FrPN2Oc2gtPa1AZJHlhvkd7xlRe4orxM2auJJc,3979
|
|
22
|
+
avtomatika/s3.py,sha256=d-zyqdS0dV6K_92BbOH4Lo0Um0AvrMxfSFoD5QFPBSo,11941
|
|
23
|
+
avtomatika/scheduler.py,sha256=F5Kv5Rx34nDd0mE5jxjwpjRg8duDZBEr91N5Y6CNR24,4231
|
|
24
|
+
avtomatika/scheduler_config_loader.py,sha256=F6mLM8yPRgG4bMHV_WnXX7UOrXD8fCXJT30bbEuQ2mk,1311
|
|
25
|
+
avtomatika/security.py,sha256=kkU68YmLWq1ClMUdEW98pS9WsEwHinHoZcdMoPm63Uk,4417
|
|
26
|
+
avtomatika/telemetry.py,sha256=ZBt1_xJ36PzDSz-zdCXeNp58NiezUgbqvMctTG25PT0,2352
|
|
27
|
+
avtomatika/watcher.py,sha256=-oqyUKq4WYtFYe0PjfDkAjjTUxpyN79JTnOzwlg-Z84,3467
|
|
28
|
+
avtomatika/worker_config_loader.py,sha256=n0j8gfuJDacWONr8744RsHTCWpc_1ZTRMC-rJZh6P6A,2249
|
|
29
|
+
avtomatika/ws_manager.py,sha256=fjIGWZF_L5j5QEpTdNT2Qz4N5ut9pjKlgEKI0sY2GOc,3148
|
|
30
|
+
avtomatika/api/handlers.py,sha256=MO6QkbT001jj4latUXGT0hGOmQf_6TkRkmwx19OcXeQ,22176
|
|
31
|
+
avtomatika/api/routes.py,sha256=vSwj2jJlmftZrjrctt-mNYLF23CfCtlUfaMoZzNOqCk,4895
|
|
32
|
+
avtomatika/history/base.py,sha256=RsCvCkHK1teHjXSk9ZHVEtpQlIjz8kWsfKYHVnapf6c,3848
|
|
33
|
+
avtomatika/history/noop.py,sha256=hLzt0RblsrKUtoyQNauOni6jCi-IYCWEPsiR0vh7tho,1226
|
|
34
|
+
avtomatika/history/postgres.py,sha256=T0XpDurnh48pPI-2JhB285GdNIexNkCSu8ExhLJzcxc,9538
|
|
35
|
+
avtomatika/history/sqlite.py,sha256=txWax9RVzBQzIZuU-SjHnEXEzBmGzIjqzoVsK2oyiAQ,9252
|
|
36
|
+
avtomatika/storage/__init__.py,sha256=mGRj_40dWZ7R7uYbqC6gCsUWCKHAbZz4ZVIhYg5dT_E,262
|
|
37
|
+
avtomatika/storage/base.py,sha256=l6ppbvbIshb5cD0yByDAeCSePBWp05iuaovbi4gaWww,12939
|
|
38
|
+
avtomatika/storage/memory.py,sha256=cZRVHqXRn3Gm06jJirBOk2IgB-ocqaJQSmzUEsCmK-M,14009
|
|
39
|
+
avtomatika/storage/redis.py,sha256=WrUbDq1wC9fpFjMM0IqkbYAvmwm9-s3DmEFo8sO18FA,18664
|
|
40
|
+
avtomatika/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
|
+
avtomatika/utils/webhook_sender.py,sha256=4Ud2Tz18yV4kzfGQyDO2by8s2EIEwHkv1vtIUis9kVQ,3606
|
|
42
|
+
avtomatika-1.0b8.dist-info/licenses/LICENSE,sha256=tqCjw9Y1vbU-hLcWi__7wQstLbt2T1XWPdbQYqCxuWY,1072
|
|
43
|
+
avtomatika-1.0b8.dist-info/METADATA,sha256=AV7TG3pNVxvHyj7eyS5OTo7BXrBigb4mFCfJvtZqzTM,26382
|
|
44
|
+
avtomatika-1.0b8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
45
|
+
avtomatika-1.0b8.dist-info/top_level.txt,sha256=gLDWhA_wxHj0I6fG5X8vw9fE0HSN4hTE2dEJzeVS2x8,11
|
|
46
|
+
avtomatika-1.0b8.dist-info/RECORD,,
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
avtomatika/__init__.py,sha256=D5r3L-H06uxsY_wgfh7u9YR29QvZMer1BlvzjW9Umfo,701
|
|
2
|
-
avtomatika/api.html,sha256=RLx-D1uFCSAXIf_2WgFlSTWrWPcmonNYM-9oNanKXBg,32835
|
|
3
|
-
avtomatika/app_keys.py,sha256=hwg5IBYUsCe-tCru61z3a4-lTw98JL41SXWCmIM_YHc,1161
|
|
4
|
-
avtomatika/blueprint.py,sha256=AJ8hZkzvqkdu9aPmlJeFzuSj57L6Xm41KS9kBMGB4Vg,11827
|
|
5
|
-
avtomatika/client_config_loader.py,sha256=zVVHZlxSqZUaNpZ4zoU0T1CFYXdxy-3vKSmPcaFuHSY,2772
|
|
6
|
-
avtomatika/compression.py,sha256=bhA1kw4YrCR3I3kdquZSY0fAzCrRrjtz55uepzLUDKI,2498
|
|
7
|
-
avtomatika/config.py,sha256=Tc-vpaQS11i_JTa1pQjGuQD3R5Kj9sIf6gGJGjItBBo,2487
|
|
8
|
-
avtomatika/constants.py,sha256=WL58Nh-EY6baM9Ur_tR9merwPRGb41_klUG2V-yUUaA,963
|
|
9
|
-
avtomatika/context.py,sha256=T6Ux4Fb1DwWRGTpMNeukM51MQDQbGk2HS6Cwpc0dc1s,4248
|
|
10
|
-
avtomatika/data_types.py,sha256=odbkraTYhOo1j3ETIX8NJOy8yIwTdQ_i3juATsjroas,1424
|
|
11
|
-
avtomatika/datastore.py,sha256=gJjhZ5kxjF8pmbbPQb_qu3HPUpfy2c6T75KZ-smb_zg,545
|
|
12
|
-
avtomatika/dispatcher.py,sha256=RrUPvDnCEwAdqxrGpUUcvQZOxG8Ir1E3m9yJjkQeEig,9635
|
|
13
|
-
avtomatika/engine.py,sha256=LZBN4Z50cEITHcrzoYqPS-Rjw4WdPSKRuq-iaBipEbE,15475
|
|
14
|
-
avtomatika/executor.py,sha256=iR9NqS9IffoW692Cq5PKM0P5lmIikmQ65vx8b-D9IZQ,23098
|
|
15
|
-
avtomatika/health_checker.py,sha256=WXwvRJ-3cZC2Udc_ogsyIQp7VzcvJjq_IaqzkTdE0TE,1265
|
|
16
|
-
avtomatika/logging_config.py,sha256=Zb6f9Nri9WVWhlpuBg6Lpi5SWRLGIUmS8Dc3xD1Gg0g,2993
|
|
17
|
-
avtomatika/metrics.py,sha256=7XDhr_xMJ9JpElpZmBG7R0ml7AMdAp9UYp_W-i7tyLg,1858
|
|
18
|
-
avtomatika/py.typed,sha256=CT_L7gw2MLcQY-X0vs-xB5Vr0wzvGo7GuQYPI_qwJE8,65
|
|
19
|
-
avtomatika/quota.py,sha256=DNcaL6k0J1REeP8sVqbY9FprY_3BSr2SxM2Vf4mEqdw,1612
|
|
20
|
-
avtomatika/ratelimit.py,sha256=hFGW5oN9G6_W_jnHmopXW8bRjjzlvanY19MLghsNLE8,1306
|
|
21
|
-
avtomatika/reputation.py,sha256=IHcaIAILWZftPPmXj5En28OSDNK7U8ivQ-w30zIF8fk,3748
|
|
22
|
-
avtomatika/scheduler.py,sha256=F5Kv5Rx34nDd0mE5jxjwpjRg8duDZBEr91N5Y6CNR24,4231
|
|
23
|
-
avtomatika/scheduler_config_loader.py,sha256=F6mLM8yPRgG4bMHV_WnXX7UOrXD8fCXJT30bbEuQ2mk,1311
|
|
24
|
-
avtomatika/security.py,sha256=kkU68YmLWq1ClMUdEW98pS9WsEwHinHoZcdMoPm63Uk,4417
|
|
25
|
-
avtomatika/telemetry.py,sha256=ZBt1_xJ36PzDSz-zdCXeNp58NiezUgbqvMctTG25PT0,2352
|
|
26
|
-
avtomatika/watcher.py,sha256=WAYTjhVmXyqWZfWfQm-iFDVZFBYpNRfwgGDxa_LCnAI,3354
|
|
27
|
-
avtomatika/worker_config_loader.py,sha256=n0j8gfuJDacWONr8744RsHTCWpc_1ZTRMC-rJZh6P6A,2249
|
|
28
|
-
avtomatika/ws_manager.py,sha256=pi5xe0ivsCjRZw08ri5N-gAChMH2I2YPLpl3E2tP89k,3057
|
|
29
|
-
avtomatika/api/handlers.py,sha256=MO6QkbT001jj4latUXGT0hGOmQf_6TkRkmwx19OcXeQ,22176
|
|
30
|
-
avtomatika/api/routes.py,sha256=vSwj2jJlmftZrjrctt-mNYLF23CfCtlUfaMoZzNOqCk,4895
|
|
31
|
-
avtomatika/history/base.py,sha256=Gfw0Gb4Mt9wQrMlYLugZwey_6-cDej5OUctiMTCWg7Q,1668
|
|
32
|
-
avtomatika/history/noop.py,sha256=ETVtPiTfkaMpzhGD8c0_4Iu6pWD89dnPrrRrSIjmc8s,970
|
|
33
|
-
avtomatika/history/postgres.py,sha256=vtW4LMW7Vli5MjcGYY3ez667-C8Cq3I7kIHrcEgSYps,9409
|
|
34
|
-
avtomatika/history/sqlite.py,sha256=Blc9ckvzoDaMRStXyfJOzMAdU_t2JcwtQtVdPgnr6s0,9131
|
|
35
|
-
avtomatika/storage/__init__.py,sha256=mGRj_40dWZ7R7uYbqC6gCsUWCKHAbZz4ZVIhYg5dT_E,262
|
|
36
|
-
avtomatika/storage/base.py,sha256=hW7XFhe6CQDP69q5NPSkUzEInIFxDR1-AyRPZNPEDEc,11424
|
|
37
|
-
avtomatika/storage/memory.py,sha256=BYox_3v1qRqfJyyjkjxXj5OmyGBu0EZqz5BWKZy6YsU,12561
|
|
38
|
-
avtomatika/storage/redis.py,sha256=opOhqBL_uCsNXcMD_W_tJU-8wzDUSjBJWEsXrwP2_YM,21035
|
|
39
|
-
avtomatika/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
40
|
-
avtomatika/utils/webhook_sender.py,sha256=sbX6HEED_TvH3MBxFlVrAqP-n68y0q5quYty5b8Z4D8,1941
|
|
41
|
-
avtomatika-1.0b7.dist-info/licenses/LICENSE,sha256=tqCjw9Y1vbU-hLcWi__7wQstLbt2T1XWPdbQYqCxuWY,1072
|
|
42
|
-
avtomatika-1.0b7.dist-info/METADATA,sha256=FVUEaG5_NWobxU5_FDG2l5RmdhvVN5t1quZXQ0GsSpw,24215
|
|
43
|
-
avtomatika-1.0b7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
-
avtomatika-1.0b7.dist-info/top_level.txt,sha256=gLDWhA_wxHj0I6fG5X8vw9fE0HSN4hTE2dEJzeVS2x8,11
|
|
45
|
-
avtomatika-1.0b7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|