Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions lessons/2026-05-07-openclaw-v5.6-upgrade-completed.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,30 +115,46 @@ Backups: `*.bak-api-health-fix-20260507-151727` (do sed errado) + `*.bak-revert-

**Root cause:** working set real do nox-mem-api é ~1.3-1.5G (chunks 63727 + FTS5 vector index + sqlite-vec embeddings + caches em memória). MemoryHigh=1500M estava **ABAIXO do baseline natural**. Service carregava chunks no startup, batia no throttle imediatamente, ficava degradado pelo restante da vida útil. Restart manual não resolvia — em 6s pós-startup já estava em 1.5G de novo (3204 high events).

**Fix aplicado:** bump systemd drop-in `/etc/systemd/system/nox-mem-api.service.d/limits.conf`:
**Fix aplicado em 2 fases — bump 1 era insuficiente:**

**Bump 1 (16:51):** `MemoryHigh 1500M→1800M, MemoryMax 2G→2500M`. Backup `limits.conf.bak-pre-bump-20260507-165148`. Resultado pós-bump 5min watch: memory 1.5G estável, high events FROZEN em 4554, latency 1.0-1.2s. Aparentou resolvido.

**Recorrência (T+1h45min):** canary voltou a alertar `FAIL(2) unreachable:18802` às 18:17. Investigação:
- Service voltou a 100% MemoryHigh (1.8G/1.8G) em uptime 43min
- High events subiu **4554 → 21793** em ~1h (17K novos hits)
- Latency degradou: 3s+ sequencial, 8-13s concurrent (2 reqs paralelas)
- Working set real cresce **com uso** (caches embedding/chunk carregados pelas queries diárias) — não estabiliza em snapshot inicial

**Bump 2 (18:34):** `MemoryHigh 1800M→2400M, MemoryMax 2500M→3000M`. Backup `limits.conf.bak-pre-bump2-20260507-183456`. Config final:
```ini
[Service]
MemoryHigh=1800M # era 1500M
MemoryMax=2500M # era 2G
MemoryHigh=2400M
MemoryMax=3000M
TimeoutStopSec=20
StartLimitInterval=60s
StartLimitBurst=5
```
Sistema host: 16GB total / 11GB free → safe headroom. Backup: `limits.conf.bak-pre-bump-20260507-165148`.

**Resultado pós-bump (5min watch):**
| Métrica | Pré-bump | Pós-bump | Delta |
|---|---|---|---|
| Memory current | 1.57G | 1.5G estável | flat |
| memory.events.high | 20432 (subindo) | 4554 (FROZEN) | sem novos hits |
| Latency `/api/search` | 6s+ (pico 9s) | 1.0-1.2s | -80% |
| Canary alerts em 10min | 1 | 0 | resolvido |
**Resultado pós-bump 2 (10min watch):**
| Métrica | Pré-bump 1 | Pós-bump 1 (5min) | Recorreu (T+1h) | Pós-bump 2 (10min) |
|---|---|---|---|---|
| Memory current | 1.57G | 1.5G | **1.8G** (100% limit) | **1.7G constante** |
| memory.events.high | 20432 | 4554 (frozen) | **21793** (subindo) | **0** (zero) |
| Latency `/api/search` | 6s+ pico 9s | 1.0-1.2s | 3s+ seq, 13s concurrent | **0.9-1.5s** consistente |
| Canary status | FAIL(2) Discord | 0 disparos | FAIL(1)+FAIL(2) | 2 OKs (debounce reset) |

**Lição (P2 estratégica):** `MemoryHigh` em systemd cgroup deve ser baseado em **working set steady-state**, não em valor "confortável" ou "metade do MemoryMax". Service cuja warm-up natural excede MemoryHigh fica permanentemente throttled — pior que estar acima do limite de uma vez (zero crashes mascaram problema).
**Lição (P2 estratégica, refinada após bump 1 falhar):** `MemoryHigh` em systemd cgroup deve ser baseado em **working set steady-state revelado em horas de uso real**, não em snapshot inicial pós-restart. Bump 1 pareceu resolver em 5min de watch (memory 1.5G estável), mas working set real era 1.8G+ revelado só após 1h+ de uso normal — caches embedding/chunk crescem com queries diárias. Service cuja warm-up natural excede MemoryHigh fica permanentemente throttled — pior que estar acima do limite de uma vez (zero crashes mascaram problema).

**Diagnóstico empírico:** comparar `memory.current` (estável) vs `memory.events.high` (incrementando) em `/sys/fs/cgroup/<service>/`. Se high incrementa sem max/oom subir, é throttle silencioso.

**Padrão pra próxima service nova:** rodar 24h sob load real, observar `memory.peak` no journal `Consumed N memory peak`, MemoryHigh = peak * 1.2 minimum. Não confiar em estimativas estáticas.
**Padrão pra próxima service:**
1. Rodar **24h+ sob load real** (não 5min, não 1h — caches storage/embedding levam horas pra estabilizar)
2. Observar `memory.peak` no journal `Consumed N memory peak`
3. MemoryHigh = **peak * 1.4 minimum** (40% headroom, não 20%)
4. MemoryMax = MemoryHigh * 1.25 (margem extra)
5. Re-monitorar 24h pós-bump pra confirmar estabilidade

**Anti-padrão:** declarar resolvido após 5min observação pós-restart — restart libera cache, queries não rodaram ainda, snapshot é falsamente estável.

### Incidente 4 (não-blocante): marker mismatch reapply vs canary

Expand Down
Loading