Como Implementar Cooldown por Usuário no Bot do Discord Sem Armazenamento Externo
🔍 WiseChecker

Como Implementar Cooldown por Usuário no Bot do Discord Sem Armazenamento Externo

Você quer um bot do Discord que limite a frequência com que um usuário pode executar um comando, mas não quer usar banco de dados ou armazenamento em arquivo. Muitos desenvolvedores de bots precisam de cooldowns para evitar spam e abuso. Armazenar dados de cooldown na memória evita a configuração de Redis, SQLite ou arquivos JSON. Este artigo explica como implementar um cooldown por usuário usando o módulo time do Python e um dicionário em memória.

Principais Conclusões: Cooldown do Bot em Memória Sem Banco de Dados

  • Dicionário + time.time(): Armazene IDs de usuário e timestamps em um dicionário Python; verifique os segundos decorridos em relação ao valor do cooldown.
  • Decorator @commands.cooldown do discord.py: Limitador de taxa integrado que usa um bucket em memória; nenhum armazenamento externo necessário.
  • discord.ext.tasks.loop para limpeza: Remova periodicamente entradas expiradas do seu dicionário para evitar inchaço de memória.

ADVERTISEMENT

Entendendo o Cooldown em Memória para Bots do Discord

Um cooldown impede que um usuário execute o mesmo comando mais de uma vez dentro de um intervalo de tempo definido. Quando você usa armazenamento externo como um banco de dados, o cooldown persiste após reinicializações do bot e entre várias instâncias do bot. O cooldown em memória armazena dados apenas na RAM do processo do bot. Essa abordagem é a mais simples de codificar, não requer configuração e funciona perfeitamente para bots de instância única ou comunidades pequenas.

O mecanismo central é um dicionário Python onde cada chave é um ID de usuário e cada valor é o timestamp da última execução do comando. Quando um usuário executa um comando, o bot verifica se o tempo atual menos o timestamp armazenado é menor que a duração do cooldown. Se for verdadeiro, o bot rejeita o comando. Se for falso, o bot atualiza o timestamp e executa o comando.

Limitações do Cooldown em Memória

Todos os dados de cooldown são perdidos quando o bot reinicia. Se você executar vários processos de bot atrás de um balanceador de carga, cada processo tem seu próprio dicionário, então um usuário poderia contornar o cooldown acessando uma instância diferente. Para esses casos, você precisa de armazenamento externo. Para a maioria dos bots de processo único, o cooldown em memória é rápido e confiável.

Como Implementar um Cooldown Personalizado Usando um Dicionário

Este método oferece controle total sobre a lógica do cooldown. Você decide a mensagem de erro, a duração do cooldown por comando e se deseja aplicar cooldowns diferentes para cargos diferentes.

  1. Importe o módulo time
    Adicione import time no topo do seu script do bot. A função time.time() retorna o timestamp Unix atual em segundos.
  2. Crie um dicionário de cooldowns
    Defina um dicionário global: cooldowns = {}. Cada chave será um ID de usuário como inteiro, e cada valor será um timestamp float.
  3. Defina uma função de verificação de cooldown
    Escreva uma função que receba o ID do usuário e a duração do cooldown em segundos. Ela retorna True se o usuário puder prosseguir, False se o cooldown estiver ativo. Dentro, obtenha o tempo atual com time.time(). Consulte o ID do usuário no dicionário. Se o usuário não tiver entrada, ou se o tempo atual menos o tempo armazenado for maior que a duração, atualize a entrada e retorne True. Caso contrário, retorne False.
  4. Use a verificação dentro de um comando
    Na sua função @bot.command(), chame a verificação de cooldown no início. Se ela retornar False, envie uma mensagem de erro e use return para interromper a execução. Exemplo: if not can_proceed(ctx.author.id, 30): await ctx.send('Você deve aguardar 30 segundos entre os usos.'); return
  5. Adicione limpeza periódica para evitar crescimento de memória
    Use discord.ext.tasks.loop para executar uma função a cada poucos minutos. A função itera sobre o dicionário e remove entradas onde o timestamp é mais antigo que o cooldown máximo que você usa. Isso mantém o dicionário pequeno.

ADVERTISEMENT

Usando o Decorator de Cooldown Integrado do Discord.py

A biblioteca discord.py fornece um sistema de cooldown que também usa armazenamento em memória. É mais fácil de implementar do que um dicionário personalizado e inclui tratamento de erros automático.

  1. Importe o decorator
    Adicione from discord.ext.commands import cooldown, BucketType às suas importações.
  2. Aplique o decorator de cooldown
    Coloque @commands.cooldown(1, 30, BucketType.user) acima do seu comando. O primeiro argumento é o número de usos permitidos. O segundo é a janela de tempo em segundos. O terceiro é o tipo de bucket: BucketType.user para por usuário, BucketType.channel para por canal, BucketType.guild para por servidor, ou BucketType.default para global.
  3. Trate o erro de cooldown
    Crie um manipulador de erros para seu bot ou para uma cog. Use @bot.event e escute on_command_error. Verifique se o erro é commands.CommandOnCooldown. Se for, envie uma mensagem com o tempo restante: await ctx.send(f'Comando em cooldown. Tente novamente em {error.retry_after:.2f} segundos.')
  4. Redefina o cooldown manualmente se necessário
    Você pode redefinir o cooldown de um usuário chamando ctx.command.reset_cooldown(ctx). Isso é útil para comandos de administrador que ignoram o cooldown.

Erros Comuns e Coisas a Evitar

Dicionário Cresce Sem Limpeza

Se você nunca remover entradas antigas, o dicionário crescerá indefinidamente. Use uma tarefa periódica para excluir entradas mais antigas que seu cooldown mais longo. Por exemplo, se seu cooldown mais longo é de 3600 segundos, remova entradas mais antigas que 3600 segundos a cada 10 minutos.

Cooldown Não é Thread-Safe

Bots do Discord executam em uma única thread, então o acesso ao dicionário é seguro. Se você usar tarefas asyncio que modificam o dicionário concorrentemente, use asyncio.Lock para evitar condições de corrida. Para a maioria dos comandos, isso não é necessário.

Usando o Tipo de Bucket Errado

Se você aplicar BucketType.default, o cooldown se aplica a todos os usuários globalmente. Isso significa que o bot inteiro para de responder a esse comando pelo período de cooldown após um usuário usá-lo. Sempre use BucketType.user para cooldown por usuário.

Cooldown Persiste Após Reinicializações do Bot

O cooldown em memória não sobrevive a uma reinicialização. Se seu bot reiniciar com frequência, os usuários podem reutilizar comandos imediatamente. Se isso for um problema, mude para um banco de dados. Para a maioria dos bots, as reinicializações são raras e a troca é aceitável.

ADVERTISEMENT

Dicionário Personalizado vs Decorator Integrado: Comparação

Item Dicionário Personalizado Decorator Integrado
Esforço de configuração Escreva sua própria função de verificação Uma linha de decorator
Mensagens de erro Controle total sobre texto e formatação Deve tratar o erro CommandOnCooldown
Redefinição de cooldown Excluir manualmente a chave do dicionário Usar o método reset_cooldown()
Múltiplos comandos Cada comando precisa de sua própria verificação Cada comando recebe seu próprio decorator
Limpeza de memória Deve implementar limpeza periódica Limpeza interna automática
Tipos de bucket Apenas baseado em usuário (você codifica outros) Usuário, canal, servidor, global

Agora você pode implementar um cooldown por usuário para seu bot do Discord sem qualquer armazenamento externo. Use o método do dicionário personalizado se precisar de controle refinado sobre mensagens de erro ou durações de cooldown por cargo. Use o decorator integrado para velocidade e simplicidade. Para bots de produção que reiniciam com frequência ou executam várias instâncias, considere adicionar Redis ou SQLite para persistir dados de cooldown entre reinicializações.

ADVERTISEMENT