livrare lot 2
This commit is contained in:
commit
8ecc78e729
763 changed files with 164593 additions and 0 deletions
291
backend/services/orchestration-layer/agent-v3/MIGRATION_REDIS.md
Normal file
291
backend/services/orchestration-layer/agent-v3/MIGRATION_REDIS.md
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
# Migrare Redis: `didi-cache` local → cluster HA `10.11.50.100`
|
||||
|
||||
**Autor**: refactor 2026-04-22
|
||||
**Scop**: mutarea tuturor clienților Redis (agent-v3 + didiFramework) de pe containerul local `didi-cache` pe clusterul HA managed (rag01/02/03 cu VIP HAProxy pe `10.11.50.100`).
|
||||
|
||||
---
|
||||
|
||||
## Stare actuală (post-refactor cod, pre-cutover)
|
||||
|
||||
- Tot codul Redis e centralizat prin `createRedisConnection()` — 2 helpers paraleli:
|
||||
- `agent-v3/src/shared/redis/connection.ts`
|
||||
- `didiFramework/src/config/redis.ts`
|
||||
- Zero `new Redis({...})` inline în code — grep confirmă.
|
||||
- Suport pentru ACL (username + password) adăugat: dacă `REDIS_USERNAME` e gol, se face legacy AUTH (doar password).
|
||||
- Auto-reconnect + retryStrategy + reconnectOnError pentru READONLY/MASTERDOWN.
|
||||
- `docker-compose.yml` (agent-v3, didiFramework) au env vars cu fallback la valorile vechi (`didi-cache`, `redis123`) — deci **nimic nu s-a rupt**, rulează identic cu înainte.
|
||||
|
||||
---
|
||||
|
||||
## Target
|
||||
|
||||
| Parametru | Valoare |
|
||||
|---|---|
|
||||
| Host | `10.11.50.100` |
|
||||
| Port | `16379` |
|
||||
| Username | `didi` |
|
||||
| Password | `$CLUSTER_PASSWORD` |
|
||||
| DB | `0` |
|
||||
| Sentinel VIP | `10.11.50.100:16380` (master name `ragmaster`) — neutilizat deocamdată, folosim HAProxy VIP |
|
||||
|
||||
Strategie failover: **HAProxy VIP** (simplu). ioredis reconectează automat la VIP după failover; TCP session se rupe 2-10s. Dacă se dovedește insuficient, putem trece la Sentinel client (cod pregătit să accepte `overrides` în helper).
|
||||
|
||||
---
|
||||
|
||||
## Pre-cutover checklist
|
||||
|
||||
1. **Verificare conectivitate** din host DIDI (10.11.10.12):
|
||||
```bash
|
||||
docker exec didi-cache redis-cli -h 10.11.50.100 -p 16379 \
|
||||
--user didi --pass '$CLUSTER_PASSWORD' --no-auth-warning PING
|
||||
# Expected: PONG
|
||||
```
|
||||
|
||||
2. **Verificare din container agent-v3** (important — rețeaua Docker bridge trebuie să rutează prin host la LAN):
|
||||
```bash
|
||||
docker exec didi-agent-v3 sh -c 'apk add --no-cache redis 2>/dev/null; redis-cli -h 10.11.50.100 -p 16379 --user didi --pass "$CLUSTER_PASSWORD" --no-auth-warning PING'
|
||||
```
|
||||
Dacă eșuează, host-ul nu rutează containerul la LAN. Fix: `docker network inspect didi-network` + verifică iptables DOCKER-USER.
|
||||
|
||||
3. **Verificare replicare cluster**:
|
||||
```bash
|
||||
docker exec didi-cache redis-cli -h 10.11.50.100 -p 16379 \
|
||||
--user didi --pass '$CLUSTER_PASSWORD' --no-auth-warning INFO replication
|
||||
# Expected: role:master, connected_slaves:2
|
||||
```
|
||||
|
||||
4. **Backup Redis local** (paranoia):
|
||||
```bash
|
||||
docker exec didi-cache redis-cli -a redis123 --no-auth-warning --rdb /data/pre-migration-backup.rdb
|
||||
docker cp didi-cache:/data/pre-migration-backup.rdb ./didi-cache-backup-$(date +%F).rdb
|
||||
```
|
||||
|
||||
5. **Fereastră de mentenanță** — alege un moment cu trafic minim.
|
||||
Impact estimat:
|
||||
- 5-10s: restart services
|
||||
- <60s: primul `/api/sync-redis` să repopuleze framework config
|
||||
- Sesiuni async în zbor (`didi:queue:session:*`) — se pot pierde. Inventariere:
|
||||
```bash
|
||||
docker exec didi-cache redis-cli -a redis123 --no-auth-warning --scan --pattern 'didi:queue:session:*' | wc -l
|
||||
```
|
||||
Dacă > 0, așteaptă ca cozile RabbitMQ să se golească înainte de cutover.
|
||||
|
||||
---
|
||||
|
||||
## Pași cutover
|
||||
|
||||
### 1. Oprire workeri + API (menține Redis local live pentru rollback)
|
||||
|
||||
```bash
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/agent-v3
|
||||
docker compose stop agent-v3 worker-media-preprocess worker-techniques \
|
||||
worker-ai-tampered worker-claims worker-domain verdict-aggregator
|
||||
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/didiFramework
|
||||
docker compose stop didi-framework
|
||||
```
|
||||
|
||||
### 2. Setează env vars noi
|
||||
|
||||
Editează `/etc/didi.env` (sau altă locație shared) sau adaugă la `.env` din root-ul fiecărui compose:
|
||||
|
||||
```
|
||||
REDIS_HOST=10.11.50.100
|
||||
REDIS_PORT=16379
|
||||
REDIS_USERNAME=didi
|
||||
REDIS_PASSWORD=$CLUSTER_PASSWORD
|
||||
REDIS_DB=0
|
||||
```
|
||||
|
||||
**Recomandat**: un singur `.env` la `/home/admin365/didi_mono/backend/.env` pe care îl referențiază ambele compose-uri prin `env_file:` (necesită mică modificare in compose).
|
||||
|
||||
**Atenție**: NU committa parola în git.
|
||||
|
||||
### 3. Rebuild containere cu noul cod
|
||||
|
||||
```bash
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/agent-v3
|
||||
docker compose build agent-v3 worker-media-preprocess worker-techniques \
|
||||
worker-ai-tampered worker-claims worker-domain verdict-aggregator
|
||||
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/didiFramework
|
||||
docker compose build didi-framework
|
||||
```
|
||||
|
||||
### 4. Pornește didiFramework primul + rulează sync-redis
|
||||
|
||||
Ordinea contează: agent-v3 citește config din Redis la fiecare request. Dacă nu există config, analizele eșuează.
|
||||
|
||||
```bash
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/didiFramework
|
||||
docker compose up -d didi-framework
|
||||
|
||||
# Așteaptă să fie ready
|
||||
sleep 10
|
||||
docker compose logs didi-framework | tail -20
|
||||
|
||||
# Trigger sync-redis: PG → noul cluster Redis
|
||||
curl -X POST http://localhost:3005/api/sync-redis
|
||||
# Expected: 200 OK, { "success": true, "categories": ["techniques", "sources", ...] }
|
||||
```
|
||||
|
||||
### 5. Validează că noul cluster are datele framework
|
||||
|
||||
```bash
|
||||
docker exec didi-cache redis-cli -h 10.11.50.100 -p 16379 \
|
||||
--user didi --pass '$CLUSTER_PASSWORD' --no-auth-warning \
|
||||
--scan --pattern 'didi:framework:*'
|
||||
# Expected: 8 keys (manifest, techniques, sources, claims, verdicts, weights, providers, dimensions_compact)
|
||||
|
||||
docker exec didi-cache redis-cli -h 10.11.50.100 -p 16379 \
|
||||
--user didi --pass '$CLUSTER_PASSWORD' --no-auth-warning \
|
||||
--scan --pattern 'didi:config:*' | wc -l
|
||||
# Expected: ~30 keys
|
||||
```
|
||||
|
||||
### 6. Pornește agent-v3 + workeri
|
||||
|
||||
```bash
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/agent-v3
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 7. Smoke test
|
||||
|
||||
```bash
|
||||
# Health
|
||||
curl http://localhost:24803/api/v3/health
|
||||
|
||||
# Test analiză text scurt (sync) — verifică tot fluxul Redis
|
||||
curl -X POST http://localhost:24803/api/v3/pipeline/analyze \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"text": "Test migrare redis cluster"}' | jq '.data.session_id, .data.status'
|
||||
# Expected: session_id UUID, status: "completed"
|
||||
|
||||
# Confirmă că sesiunea e scrisă pe cluster
|
||||
SID=<session_id_de_mai_sus>
|
||||
docker exec didi-cache redis-cli -h 10.11.50.100 -p 16379 \
|
||||
--user didi --pass '$CLUSTER_PASSWORD' --no-auth-warning \
|
||||
--scan --pattern "didi:pipeline:${SID}:*"
|
||||
```
|
||||
|
||||
### 8. Monitorizare 30 min
|
||||
|
||||
```bash
|
||||
# Live logs — caută "Redis error" sau "ECONNREFUSED"
|
||||
docker compose logs -f --tail 0 agent-v3 worker-techniques worker-claims verdict-aggregator | grep -iE "redis|error"
|
||||
|
||||
# Keys growth pe noul cluster
|
||||
watch -n 5 'docker exec didi-cache redis-cli -h 10.11.50.100 -p 16379 --user didi --pass "$CLUSTER_PASSWORD" --no-auth-warning DBSIZE'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rollback plan
|
||||
|
||||
Dacă ceva crapă în primele 30 min:
|
||||
|
||||
1. **Restore env vars**:
|
||||
```bash
|
||||
# Elimină REDIS_USERNAME și revino la defaults
|
||||
unset REDIS_HOST REDIS_PORT REDIS_USERNAME REDIS_PASSWORD REDIS_DB
|
||||
# sau sterge liniile din /etc/didi.env
|
||||
```
|
||||
|
||||
2. **Restart containere**:
|
||||
```bash
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/agent-v3
|
||||
docker compose up -d --force-recreate
|
||||
|
||||
cd /home/admin365/didi_mono/backend/services/orchestration-layer/didiFramework
|
||||
docker compose up -d --force-recreate
|
||||
```
|
||||
|
||||
3. **Sync-redis pe local** să repopuleze:
|
||||
```bash
|
||||
curl -X POST http://localhost:3005/api/sync-redis
|
||||
```
|
||||
|
||||
Datele vechi sunt încă pe `didi-cache` (nu le-am șters). Maxim 30 min de analize noi se pierd.
|
||||
|
||||
---
|
||||
|
||||
## Post-cutover — FALLBACK LOCAL PĂSTRAT
|
||||
|
||||
**Containerul `didi-cache` e oprit dar NU șters** — poate fi repornit oricând ca fallback pentru dev local sau incident recovery. Volumul `didi-production-cache-data` rămâne intact.
|
||||
|
||||
### Script de switch rapid: `services/orchestration-layer/scripts/redis-switch.sh`
|
||||
|
||||
```bash
|
||||
# Arată starea curentă
|
||||
./redis-switch.sh status
|
||||
|
||||
# Switch la cluster (production)
|
||||
./redis-switch.sh cluster
|
||||
|
||||
# Switch înapoi la local (rollback sau dev)
|
||||
./redis-switch.sh local
|
||||
```
|
||||
|
||||
Ce face:
|
||||
- Rescrie `REDIS_*` în ambele `.env` files (agent-v3 + didiFramework)
|
||||
- Pentru `local`: pornește containerul `didi-cache` dacă e oprit
|
||||
- Restart `didi-framework` + `agent-v3` stack (API + 12 workeri)
|
||||
- Bootstrap auto-populează Redis-ul ales dacă e gol
|
||||
|
||||
### Cum rămâne imaginea locală disponibilă:
|
||||
|
||||
- `didi-cache` definit în `production/docker-compose.yml` — **nu șterge secțiunea**
|
||||
- Image: `redis:7-alpine` (standard, disponibil oricând)
|
||||
- Volum: `didi-production-cache-data` (păstrat cu datele vechi)
|
||||
- Parolă: `redis123` (hardcodată în `REDIS_HOSTS` al Redis Commander pentru vizualizare)
|
||||
|
||||
Chiar și dacă clusterul cade complet, rollback-ul e **30 secunde**: `./redis-switch.sh local`.
|
||||
|
||||
### Cleanup DEFINITIV (când cluster e stable 30+ zile și nu mai vrei fallback):
|
||||
|
||||
1. **Oprește și șterge containerul `didi-cache`**:
|
||||
```bash
|
||||
docker stop didi-cache
|
||||
docker rm didi-cache
|
||||
docker volume rm didi-production-cache-data # păstrează ca backup încă 30 zile dacă ești paranoic
|
||||
```
|
||||
|
||||
2. **Curăță `production/docker-compose.yml`** — șterge secțiunea `didi-cache`.
|
||||
|
||||
3. **Redis Commander** — update `REDIS_HOSTS` în `data-layer/docker-compose.yml`:
|
||||
```yaml
|
||||
REDIS_HOSTS: "production:10.11.50.100:16379:0:didi:$CLUSTER_PASSWORD"
|
||||
```
|
||||
Sau deschide UI-ul nativ al cluster-ului dacă există.
|
||||
|
||||
4. **Update documentație**:
|
||||
- `agent-v3/INDEX.md`: înlocuiește `didi-cache:6379` cu `10.11.50.100:16379`
|
||||
- `didiCache/INDEX.md`: marchează drept deprecated / legacy
|
||||
- `project_network_architecture.md`: actualizează diagrama
|
||||
|
||||
---
|
||||
|
||||
## Riscuri reziduale
|
||||
|
||||
| Risc | Probabilitate | Mitigare |
|
||||
|---|---|---|
|
||||
| Containerele nu pot rezolva `10.11.50.100` din docker-network | Mică (testat din didi-cache — OK) | Test forțat pre-cutover, fallback network_mode: host pe un worker dacă e nevoie |
|
||||
| Failover cluster exact în timpul cutover-ului | Foarte mică | retryStrategy cu 5s max + reconnectOnError — ioredis recuperează |
|
||||
| Cluster partajat cu alte proiecte și overwrite-uri accidentale | Necunoscut | Toate cheile DIDI încep cu `didi:*` sau `agent:*`. Recomand confirmare de la admin cluster că DB 0 e dedicat |
|
||||
| Parola hardcodată în .env committed în git | Umană | `.gitignore` `.env` + folosește `.env.example` fără parole |
|
||||
| Discrepanță `maxmemory` pe cluster (noeviction) → OOM la volum mare | Mică (13MB actuali) | Monitorizare `INFO memory` săptămânală |
|
||||
|
||||
---
|
||||
|
||||
## Verificare finală post-migrare
|
||||
|
||||
Checklist de confirmat înainte de cleanup:
|
||||
|
||||
- [ ] `DBSIZE` pe cluster nou crește în timp (sesiuni acumulate)
|
||||
- [ ] `didi:framework:*` prezent (8 chei)
|
||||
- [ ] `didi:config:*` prezent (~30 chei)
|
||||
- [ ] Zero `Redis error` în logs în ultimele 24h
|
||||
- [ ] Test analiză text + media + URL — toate completează cu status `completed`
|
||||
- [ ] Admin dashboard `/admin/framework` load-ează normal (citește prin didiFramework → Redis)
|
||||
- [ ] Failover test: oprește temporar master-ul cluster (dacă e permis) → workers reconectează în < 10s
|
||||
Loading…
Add table
Add a link
Reference in a new issue