O que é o ursinho que fica bravo
O ursinho que fica bravo não é nenhuma biblioteca open-source famosa, nem um framework, nem uma ferramenta que você baixa do npm ou pip. É um jeito que algumas equipes usam internamente pra chamar aquele script ou aquele processo que simplesmente trava, sobe a CPU e não responde mais. Eu uso esse termo no meu círculo desde 2018, quando um job do Airflow ficava preso em loop infinito e eu comecei a marcar os tickets como "ursinho bravo" pra não precisar escrever relatório todo dia. Se você procura um repositório no GitHub com esse nome, provavelmente vai encontrar só memes ou projetos acadêmicos isolados. Nada com release estável, nada com documentação séria. O que existe de prático é o comportamento em si, que é muito comum em pipelines de dados e jobs batch.
Como identificar quando o ursinho que fica bravo está ativo
Você percebe pelo sintoma, não pelo log. A memória do container sobe até o limite, o processo entra em estado D no Linux, e às vezes o kswapd passa a consumir 100% de uma CPU só. Eu já vi isso acontecer num job de transformação Python que lia um CSV de 47 GB direto pro RAM sem chunking. O ursinho ficou bravo durante 6 horas seguidas e só saiu quando o node inteiro congelou. O diagnóstico rápido que eu faço é: olha o vsize e o rss do processo. Se o vsize for muito maior que o rss e o estado não for Running, provavelmente é memory pressure com swapped pages. Se o rss estiver estável mas a CPU continuar alta, pode ser um loop computacional ou um deadlock em thread.
O procedimento que funciona na prática
A primeira coisa que todo mundo faz errado é dar kill -9 imediato. Eu também fazia isso no começo e perdia dados de checkpoint com frequência. O jeito que eu recomendo, depois de testar várias abordagens, é esse aqui. Você entra no servidor ou no pod afetado e roda um top ou htop para confirmar o processo. Anota o PID. Depois executa kill -SIGUSR1 primeiro, porque muitos processos bem comportados tratam esse sinal escrevendo um stack trace em log antes de finalizar de verdade. Se for um job do Spark ou do Airflow, o SIGUSR1 às vezes dispara um dump de fila que é útil pra análise pós-mortem.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Se o sinal não surtir efeito em 30 segundos, aí sim você parte pra kill -SIGTERM. O timeout padrão do Kubernetes é 30 segundos também, então se você está num cluster, pode deixar que o grace period faça o trabalho. Eu já vi gente insistir com SIGKILL logo de cara e o orquestrador ter que forçar a remoção do pod manualmente depois, o que gasta uns 5 minutos a mais por incidente. O ponto que ninguém conta é o estado pós-killer. Quando o processo morre, o arquivo de lock ou o checkpoint pode ficar corrompido. No meu caso, trabalhei num pipeline de ingestão com PostgreSQL e o ursinho que fica bravo deixava o pg_locks travado com transações abertas há horas. A solução foi rodar SELECT pg_terminate_backend(pid) nos backends bloqueados antes de reiniciar o job. Sem isso, o restart simplesmente entrava em deadlock novamente.
O problema que eu encontrei e o workaround que usei
Uma vez, em outubro de 2022, o ursinho que fica bravo apareceu num job de manutenção de índices PostgreSQL que rodava todo domingo de madrugada. O processo não travava na memória, travava na rede. O I/O wait subia a 90% e o PostgreSQL entrava em modo de recovery porque o checkpoint atingia o disco de forma síncrona demais. Eu tentei ajustar checkpoint_timeout e max_wal_size, mas o problema persistia porque o disco era um EBS gp2 com IOPS base baixos. O workaround que funcionou foi dividir o job em três etapas menores com um sleep de 120 segundos entre elas, mais fsync = off temporário durante a janela de manutenção, emigration do tablespace para um volume io1. O tempo total do job caiu de 4h20min para 38 minutos e o ursinho parou de ficar bravo. O custode storage foi Irrelevante porque era só uso mensal.
Alternativas quando o ursinho que fica bravo aparece com frequência
Se o problema se repete todo semana, o jeito não é brigar com o processo, é mudar a arquitetura. Os cenários mais comuns que eu vejo são: leitura sem paginação de datasets grandes, conexões de banco não fechadas em loops, e workers síncronos processando filas gigantes sem fila real. Para Python, usar polars no lugar de pandas para dataframes acima de 2 GB já resolve metade dos casos. Para jobs batch genéricos, colocar um celery ou rq com retry com exponencial backoff evita que o processo entre em estado de pânico quando algo sobe de volume inesperadamente. E se você está em Kubernetes, garantir que o limitRange e o ResourceQuota estejam configurados impede que um único ursinho consuma tudo antes do operador perceber.
Não existe download de ursinho que fica bravo porque ele não é software. É um comportamento. O que você baixa são as práticas que evitam que ele apareça, ou as ferramentas que matam ele rápido quando aparece. Comece pelos sinais, ajuste os timeouts, e só depois pense em remanejar o workload. O resto é especulação.