🚀 NATS JetStream: K8s deployment + streams + job schema v1
- K8s deployment (2 replicas, PVC, initContainer для server_name) - Streams definitions (MM_ONLINE, MM_OFFLINE, MM_WRITE, MM_EVENTS) - Job payload schema (JSON v1 з idempotency) - Worker contract (capabilities + ack/retry) - Init streams script - Оновлено ARCHITECTURE-150-NODES.md (Control-plane vs Data-plane) TODO: Auth (nkeys), 3+ replicas для prod, worker-daemon implementation
This commit is contained in:
164
infrastructure/nats/worker-contract.md
Normal file
164
infrastructure/nats/worker-contract.md
Normal file
@@ -0,0 +1,164 @@
|
||||
# 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*
|
||||
Reference in New Issue
Block a user