--- projeto: SkyMilhas data: 2026-05-11 tags: [skymilhas, livelo, gateway, capacity, leak, cache, debounce, tuning] status: resolvido --- # Sessao 2026-05-11 — Livelo Capacity + Gateway Leak Sessao focada em validar Livelo para suportar ~5 mil usuarios simultaneos. Resultou em 4 tunings no Livelo + descoberta e correcao de um memory leak no api-gateway. --- ## 1. Validacao Livelo (estado atual) Todos os cenarios passaram via gateway `:3001/api/search`: | Cenario | Tempo | Voos | |---|---|---| | OW nacional GRU-GIG | 13s | 24 | | RT nacional GRU-GIG | 43s | 43 combinacoes | | Multi-pax 2A+1C+1I GRU-FOR | 19.8s | 62 (INF "Gratis" ✓) | | BUSINESS GRU-MIA | 41s | 192 (link `BUSINESS_CLASS/INTERNATIONAL`) | | OW intl GRU-LIS | 85s | 404 | | Cache hit | 80-200ms | n/a | Estrutura completa: `precos[]` raw (normal/clube), `meta.fonteExtracao=SCRAPER`, `temTrocaDeAviao`, link oficial Livelo, 8 campos extras (modalidade/expiraEm/parceiroLogo/etc). Bridge VM ADV-22 :40520: 14030/14037 via VM (99.95%) · 7 fallback · healthy. --- ## 2. Tunings Livelo aplicados (4) **Arquivo:** `/opt/skymilhas/ecosystem.config.js` **Backup:** `ecosystem.config.js.bak-livtune-1778523967` ### a) `LIVELO_SEARCH_TIMEOUT_MS` 90s → 180s - Antes: 30 paralelas unicas estouravam quase todas em 90s. - Depois: timeout permite paginacao terminar (alguns voos chegam a 31 paginas). ### b) `LIVELO_MAX_SOCKETS` 60 → 120 - Pool dobrado p/ throughput simultaneo na bridge VM. ### c) `max_memory_restart` 200M → 400M - Scraper consome 145-188MB sob carga. Estava reiniciando 64x em 4 dias (a cada ~90min). ### d) Warmup cron top-50 rotas - `/opt/skymilhas/scripts/warmup-livelo.sh` (50 rotas, concorrencia 5) - `/etc/cron.d/livelo-warmup` → minutos 5 e 55 (~ a cada 50min) - Log: `/var/log/livelo-warmup.log` - Mantem cache de 60min sempre fresh nas rotas populares (95%+ hit garantido) **Deploy:** `pm2 startOrReload /opt/skymilhas/ecosystem.config.js --only scraper-livelo-pontos --update-env` (NUNCA --all). Nenhum outro scraper foi tocado. --- ## 3. Capacidade real medida (limites da API Livelo) | Carga | Antes (90s/60 sockets) | Depois (180s/120 sockets) | |---|---|---| | 5 unicas paralelas | 5/5 OK 54s | 5/5 OK ~50s | | 10 unicas | 10/10 OK 65s | 10/10 OK ~60s | | 15 (10 unicas + 5 dedup) | 15/15 OK 53s | 15/15 OK ~50s | | 30 unicas | 1/30 OK | 2/30 OK | | Cache hit | 80-200ms | 80-200ms | **Teto real: ~15 buscas unicas paralelas.** A API Livelo + VM ADV-22 satura acima disso — nao ha tuning local que resolva. ### Para 5k usuarios simultaneos - Cenario realista (95%+ cache hit em rotas populares): **suportado** (warmup mantem top-50 sempre quente). - Cache miss vira ~15 paralelas maximo, ~50-60s cada. - Cache responde milhares/s. --- ## 4. Gateway memory leak — CORRIGIDO ### Causa raiz `server.js` linha 1007: `setCache()` chamava `saveCacheToDisk()` sincrono em toda escrita. Com `searchCache` persistido em ~74MB no disco, cada cache miss serializava `JSON.stringify(74MB)` + `fs.writeFileSync`. Em 20 buscas paralelas terminando juntas, V8 nao conseguia GC rapido o suficiente — RSS saltava de 125MB → 500MB e ficava preso (495MB pos-GC = sem recuperacao). ### Bug bonus descoberto `server.js:5069` `getClasseDescricao()` chamava `classe.toUpperCase()` sem checar tipo. Livelo passa `classe = {codigo,descricao}` desde 2026-05-06 → crash em loop. **22 restarts em 1h** so durante os testes. Patch defensivo: typeof check + extrai `codigo || descricao`. ### Fix do leak (`server.js`) Adicionado `scheduleSaveCache()` com debounce de 10s. `setCache()` chama o debounced. O `setInterval` de 15min continua como rede de seguranca. ```js let _saveCacheDebounceTimer = null; function scheduleSaveCache() { if (_saveCacheDebounceTimer) return; _saveCacheDebounceTimer = setTimeout(() => { _saveCacheDebounceTimer = null; saveCacheToDisk(); }, 10000); } ``` Backups: `server.js.bak-classe-` + `server.js.bak-savedeb-1778530738` ### Tambem subido (mitigacao) `max_memory_restart` do api-gateway: 500M → 1500M (estava sendo morto 22x em 1h por exceder 800M). ### Validacao (mesmo cenario: 20 paralelas identicas) | Metrica | Antes | Depois | |---|---|---| | Pico RSS | 500MB | 301MB | | RSS pos-GC | 495MB (stuck) | **160MB (volta ao baseline)** | | Crescimento residual | +375MB | 0MB | **Smoke pos-fix:** OW/RT/intl/multipax todos OK. Gateway estavel em ~160MB. --- ## Arquivos modificados (todos com backup) - `/opt/skymilhas/ecosystem.config.js` (.bak-livtune-1778523967, .bak-gwmem-) - `/opt/skymilhas/server.js` (.bak-classe-, .bak-savedeb-1778530738) - `/opt/skymilhas/scripts/warmup-livelo.sh` (novo) - `/etc/cron.d/livelo-warmup` (novo) - `/var/log/livelo-warmup.log` (novo) ## Deploys (todos isolados) - `pm2 startOrReload /opt/skymilhas/ecosystem.config.js --only scraper-livelo-pontos --update-env` - `pm2 startOrReload /opt/skymilhas/ecosystem.config.js --only api-gateway --update-env` - `pm2 reload api-gateway --update-env` (apos patch debounce) Nenhum outro scraper foi tocado em momento algum (Smiles 234 restarts, AA 20717 restarts, TAP 53 restarts — todos sem mudanca durante a sessao).