# Worker Contract v1 — Memory Module **Дата:** 2026-01-10 **Версія:** 1.0.0 --- ## 📋 Capability Registry Кожен воркер реєструється з наступними capabilities: ```json { "node_id": "node-123", "tier": "A|B|C", "region": "eu-west", "trust_zone": "internal", "hardware": { "cpu_cores": 32, "ram_gb": 128, "gpu": true, "gpu_model": "RTX 3090", "vram_gb": 24, "cuda_version": "13.0" }, "capabilities": { "max_batch": 1000, "max_tokens": 8192, "models": ["embed-multilingual-v3.0", "llama3:8b"], "embedding_dim": 1024, "supported_jobs": ["embed", "summarize", "index"] }, "status": "ready|busy|maintenance", "last_heartbeat": "2026-01-10T19:30:00Z" } ``` ### Реєстрація - **Postgres** (таблиця `worker_capabilities`) або **Consul** (KV store) - Heartbeat кожні 30 секунд - Якщо heartbeat пропущено > 90 секунд → worker вважається offline --- ## 🔄 Job Execution Flow ### 1. Pull Model Воркер сам вирішує "чи брати job": - Підписка на consumer (durable) - Перевірка `requirements` vs власні `capabilities` - Якщо підходить → бере job, інакше пропускає ### 2. Execution ```python async def execute_job(job: JobPayload): # 1. Перевірка requirements if not can_fulfill(job.requirements, my_capabilities): await msg.nak() # Negative ack, не підходить return # 2. Виконання try: result = await process_job(job) # 3. Запис результату await write_result(job, result) # 4. ACK await msg.ack() except RetryableError as e: await msg.nak(delay=e.backoff) except FatalError as e: await msg.ack() # ACK щоб не retry await log_error(job, e) ``` ### 3. ACK/NAK Policy - **ACK** — job виконано успішно - **NAK** — job не виконано, потрібен retry - **NAK(delay)** — retry з затримкою - **Timeout** — якщо `ack_wait` вийшов → автоматичний retry --- ## 📊 Consumer Policies ### Online Consumer (Tier A) ```yaml stream: MM_ONLINE consumer: online-worker-tier-a ack_wait: 30s max_ack_pending: 5000 concurrency: 50-200 (per worker) filter: tier=A AND needs_gpu=true (для GPU jobs) ``` **Worker Selection:** - Тільки `tier=A` - `needs_gpu=true` → тільки GPU воркери - `max_latency_ms` перевірка ### Offline Consumer (Tier B) ```yaml stream: MM_OFFLINE consumer: offline-worker-tier-b ack_wait: 5-30 min max_ack_pending: 10000 concurrency: висока, але з backpressure ``` **Backpressure:** - Якщо online backlog росте → обмежити offline concurrency - Preemption: offline jobs можуть бути призупинені для online --- ## 🔍 Idempotency **Обов'язково:** кожен job має `idempotency_key` (SHA256 hash). **Перевірка:** - Перед виконанням перевірити в Postgres: чи вже виконано? - Якщо так → повернути кешований результат - Якщо ні → виконати та зберегти результат **TTL:** idempotency keys зберігаються 7 днів. --- ## 📈 Metrics & Alerts ### Worker Metrics - `worker_jobs_processed_total{type, status}` - `worker_job_duration_seconds{type, quantile}` - `worker_gpu_utilization{node_id}` - `worker_vram_usage_bytes{node_id}` - `worker_errors_total{type, error_type}` ### NATS Metrics - `nats_consumer_lag{stream, consumer}` - `nats_redeliveries_total{stream}` - `nats_ack_pending{stream, consumer}` - `nats_stream_storage_bytes{stream}` ### Alerts → Matrix Ops Room - `MM_ONLINE backlog > 1000` (SLO порушення) - `redeliveries spike > 100/min` - `embed p95 > 500ms` (target: 300ms) - `disk > 80%` на JetStream PVC - `worker offline > 2 min` (Tier A) --- *Документ створено: 2026-01-10 19:30 CET*