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.
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.
- Importe o módulo time
Adicioneimport timeno topo do seu script do bot. A funçãotime.time()retorna o timestamp Unix atual em segundos. - 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. - 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 retornaTruese o usuário puder prosseguir,Falsese o cooldown estiver ativo. Dentro, obtenha o tempo atual comtime.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 retorneTrue. Caso contrário, retorneFalse. - 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 retornarFalse, envie uma mensagem de erro e usereturnpara 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 - Adicione limpeza periódica para evitar crescimento de memória
Usediscord.ext.tasks.looppara 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.
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.
- Importe o decorator
Adicionefrom discord.ext.commands import cooldown, BucketTypeàs suas importações. - 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.userpara por usuário,BucketType.channelpara por canal,BucketType.guildpara por servidor, ouBucketType.defaultpara global. - Trate o erro de cooldown
Crie um manipulador de erros para seu bot ou para uma cog. Use@bot.evente escuteon_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.') - Redefina o cooldown manualmente se necessário
Você pode redefinir o cooldown de um usuário chamandoctx.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.
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.