Ciclo de Reciclagem de Workers
Workers persistentes acumulam memória fragmentada ao longo do tempo. Em vez de aguardar o sistema operacional matar bruscamente o processo com SIGKILL (cancelando requisições de clientes em andamento), o Leakless implementa a Reciclagem Graciosa de Workers com proteção nativa contra tempestades de reinício (restart storms).
Condições de Disparo
Um worker é avaliado para reciclagem sob um modelo resiliente de Dois Níveis:
Drift de Memória Relativo (
maxDriftMb&consecutiveViolationsThreshold) [Primário]:- Mede o Resident Set Size real do Linux (
/proc/self/statm) em relação à memória base inicial do worker ($M_0$). - Quando o crescimento ultrapassa o limite (
maxDriftMb: 64MB), o Leakless executagc_collect_cycles()e reavalia a memória física. - Se a violação persistir por $N$ requisições consecutivas (
consecutive_violations: 5), a reciclagem é confirmada. - Proteção por Cooldown (
recycle_cooldown: 10s): Limita a frequência de reinicializações por worker, impedindo que todos os workers caiam juntos sob rajadas de tráfego. - Jitter (
drift_jitter: 10%): Aplica uma pequena variação pseudo-aleatória no teto de drift para desincronizar reinicializações.
- Mede o Resident Set Size real do Linux (
Teto de Emergência Físico (
maxRssMb) [Opcional / Emergência]:- Teto físico absoluto (ex:
512MB) para proteger o container contra o Linux OOM KillerSIGKILLem caso de vazamentos descontrolados.
- Teto físico absoluto (ex:
Limite de Requisições (
maxRequests):- A contagem total de requisições atendidas pelo worker atinge o limite (ex:
1000 requisições).
- A contagem total de requisições atendidas pelo worker atinge o limite (ex:
O Fluxo de Reciclagem
- Conclusão da Requisição Ativa: A requisição em andamento executa normalmente, gera a resposta HTTP e a envia ao cliente.
- Auditoria no
endRequest(): O Leakless executa os rollbacks de transação, restauração de fuso horário, reavaliação pós-GC e cálculo de drift. - Sinalização Graciosa:
- No Laravel Octane: Sinaliza o runner do Octane para reciclar o worker de forma não bloqueante.
- No Vanilla FrankenPHP: O
FrankenPhp::run()quebra o loop e sai graciosamente (exit(0)), permitindo que o FrankenPHP crie um novo processo.
Exemplo de Configuração
php
use TheMattos\Leakless\DTOs\Config;
$config = new Config(
maxDriftMb: 64, // Permite até 64MB de crescimento relativo
consecutiveViolationsThreshold: 5, // Exige 5 violações consecutivas pós-GC
recycleCooldownSeconds: 10, // Janela de cooldown entre reinicializações (segundos)
maxRequests: 1000, // Recicla após 1.000 requisições processadas
);