← Blog

12 de outubro de 2026

O bug que travava meu bot por 90 segundos

Uma linha síncrona dentro de um bot assíncrono derrubava a conexão com o Discord. Como achei e como resolvi.

Os bots da Codraise rodam 24/7. De vez em quando um deles simplesmente sumia: parava de responder, o Discord marcava como reconectando e, uns 90 segundos depois, ele voltava como se nada tivesse acontecido.

Sem erro, sem traceback, sem crash. O pior tipo de bug.

O sintoma

O log mostrava sempre a mesma coisa antes do sumiço:

Shard ID None heartbeat blocked for more than 10 seconds.

Essa mensagem do discord.py é uma pista enorme. Ela quer dizer que o event loop ficou travado: alguma coisa ocupou a thread principal e o bot não conseguiu mandar o heartbeat pro Discord. Sem heartbeat, o Discord derruba a conexão.

O culpado

Em asyncio, tudo roda numa thread só. Se uma função síncrona e lenta roda dentro de uma corrotina, ela segura todo mundo: comandos, eventos, heartbeat.

No meu caso era o leitor de RSS de notícias:

async def buscar_noticias():
    feed = feedparser.parse(URL_DO_FEED)  # síncrono: faz a requisição HTTP aqui mesmo
    ...

feedparser.parse baixa o feed na hora, de forma bloqueante. Quando o site do feed demorava a responder, o bot inteiro ficava parado esperando.

A correção

Mandar o trabalho pesado pra outra thread com asyncio.to_thread, e colocar cache pra não buscar o mesmo feed toda hora:

import asyncio, time

_cache = {"quando": 0.0, "feed": None}

async def buscar_noticias():
    if time.time() - _cache["quando"] < 600:
        return _cache["feed"]
    feed = await asyncio.to_thread(feedparser.parse, URL_DO_FEED)
    _cache.update(quando=time.time(), feed=feed)
    return feed

Agora o download acontece fora do event loop e o bot continua respondendo enquanto espera.

A regra que ficou

Depois disso virou regra nos meus bots: qualquer coisa pesada vai pra to_thread. Requisição com biblioteca síncrona, renderização de imagem com Pillow, leitura de arquivo grande, tudo. Se aparecer heartbeat blocked, a primeira pergunta é: o que está rodando síncrono dentro de um async def?

Curtiu? Esse tipo de conversa rola todo dia na Codraise.

Conhecer a comunidade →
visitante@francodes.dev: ~
❯