aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord Botları

Discord Bot Cooldown ve Spam Koruması Rehberi

Bir Discord botu büyüdükçe en sık karşılaşılan sorunlardan biri komut taşmasıdır: bir kullanıcı aynı komutu saniyede onlarca kez tetikler, bot da her seferinde cevap verir. Sağlam bir discord bot cooldown sistemi tam burada devreye girer; her kullanıcıya bir komutu yeniden çalıştırması için kısa bir bekleme süresi tanır ve hem botunuzu hem de Discord'un API limitlerini korur. Bu rehberde cooldown mantığını sıfırdan kurup, discord.js ile çalışan gerçek bir örnek yazacağız ve spam'a karşı ek katmanlar ekleyeceğiz.

Neden cooldown ve spam koruması gerekir?

Cooldown sadece bir "kullanıcıyı yavaşlatma" özelliği değildir; botunuzun istikrarı için bir savunma hattıdır. Başlıca nedenler:

  • API rate limit'leri: Discord, botların gönderebileceği istek sayısını sınırlar. Aşırı mesaj/yanıt gönderirseniz 429 Too Many Requests cevabı alır ve geçici olarak engellenirsiniz.
  • Kaynak tüketimi: Veritabanı sorgusu, harici API çağrısı veya görsel üretimi gibi pahalı komutlar spam'le sunucunuzu kilitleyebilir.
  • Kötüye kullanım: Ekonomi, çekiliş veya ödül komutlarında cooldown olmazsa kullanıcılar sistemi suistimal eder.
  • Kanal kirliliği: Tekrar eden bot yanıtları kanalları okunmaz hale getirir.

Cooldown mantığı: zaman damgasını saklamak

Tüm cooldown sistemlerinin temelinde tek bir fikir vardır: bir kullanıcının komutu en son ne zaman çalıştırdığını saklamak ve aradan yeterli süre geçip geçmediğini kontrol etmek. Sözde kod şöyle işler:

  • Kullanıcı komutu çalıştırır.
  • O kullanıcı için kayıtlı bir zaman damgası var mı diye bak.
  • Varsa ve (şimdi - kayıtlı zaman) < cooldown ise: reddet ve kalan süreyi söyle.
  • Aksi halde: komutu çalıştır ve yeni zaman damgasını kaydet.

Saklama yeri için küçük botlarda bellek (bir Map) yeterlidir. Bot yeniden başlatıldığında cooldown'ların sıfırlanmasını istemiyorsanız Redis veya bir veritabanı kullanın.

discord.js ile komut bazlı cooldown sistemi

discord.js v14'te slash komutları için yaygın ve resmi olarak önerilen yaklaşım, her komut için ayrı bir Collection tutmaktır. Collection, JavaScript'in Map sınıfını genişletir. Komut dosyanıza isteğe bağlı bir cooldown alanı ekleyebilirsiniz:

// commands/ping.js
const { SlashCommandBuilder } = require('discord.js');

module.exports = {
  cooldown: 5, // saniye
  data: new SlashCommandBuilder()
    .setName('ping')
    .setDescription('Botun gecikmesini gösterir'),
  async execute(interaction) {
    await interaction.reply(`Pong! ${interaction.client.ws.ping}ms`);
  },
};

Asıl kontrol, interactionCreate olayında komut çalıştırılmadan önce yapılır:

// events/interactionCreate.js
const { Events, Collection } = require('discord.js');

module.exports = {
  name: Events.InteractionCreate,
  async execute(interaction) {
    if (!interaction.isChatInputCommand()) return;

    const command = interaction.client.commands.get(interaction.commandName);
    if (!command) return;

    const { cooldowns } = interaction.client;
    if (!cooldowns.has(command.data.name)) {
      cooldowns.set(command.data.name, new Collection());
    }

    const now = Date.now();
    const timestamps = cooldowns.get(command.data.name);
    const cooldownAmount = (command.cooldown ?? 3) * 1000;

    if (timestamps.has(interaction.user.id)) {
      const expiration = timestamps.get(interaction.user.id) + cooldownAmount;
      if (now < expiration) {
        const expiredTimestamp = Math.round(expiration / 1000);
        return interaction.reply({
          content: `Bu komutu tekrar kullanmak icin bekle. Yeniden <t:${expiredTimestamp}:R> kullanabilirsin.`,
          ephemeral: true,
        });
      }
    }

    timestamps.set(interaction.user.id, now);
    setTimeout(() => timestamps.delete(interaction.user.id), cooldownAmount);

    try {
      await command.execute(interaction);
    } catch (error) {
      console.error(error);
    }
  },
};

Burada client.cooldowns kümesini başta bir kez tanımlamayı unutmayın: bot istemcinizi kurarken client.cooldowns = new Collection(); satırını ekleyin. <t:...:R> Discord'un göreli zaman damgası biçimidir ve kullanıcıya "3 saniye sonra" gibi otomatik güncellenen bir metin gösterir.

Kullanıcı, sunucu ve global cooldown türleri

Yukarıdaki örnek kullanıcı başına cooldown uygular ki en yaygın ihtiyaç budur. Ancak farklı senaryolar farklı anahtarlar gerektirir:

  • Kullanıcı başına: Anahtar olarak interaction.user.id kullanın. Kişisel komutlar (profil, bakiye) için idealdir.
  • Sunucu başına: Anahtar olarak interaction.guildId kullanın. Tüm sunucuyu etkileyen komutlarda (duyuru, toplu işlem) mantıklıdır.
  • Kanal başına: interaction.channelId ile belirli kanallarda hız sınırı koyun.
  • Global: Sabit bir anahtar (örn. komut adı) kullanın; pahalı bir harici API'yi koruyan komutlar için.

Sadece anahtar olarak hangi alanı sakladığınızı değiştirerek aynı mantığı yeniden kullanabilirsiniz. Birden çok türü birleştirmek için bileşik anahtar oluşturun: `${interaction.guildId}-${interaction.user.id}`.

Discord'un kendi rate limit'leri (429) ve discord.js

Kendi cooldown'unuz, kullanıcıların botu spamlamasını engeller; ama botun kendisi de Discord API'sine karşı limitlere tabidir. İyi haber: discord.js'in altında çalışan @discordjs/rest katmanı, global ve route bazlı rate limit'leri otomatik yönetir, istekleri kuyruğa alır ve 429 durumunda bekler. Yine de bilmeniz gereken noktalar var:

  • Bir döngü içinde yüzlerce mesaj göndermeyin; bunun yerine işlemleri toplu hale getirin veya araya gecikme koyun.
  • Geçici sohbet yanıtlarında (yalnızca komutu çalıştıran kişinin gördüğü) ephemeral: true kullanmak kanal kirliliğini ve gereksiz mesaj trafiğini azaltır.
  • Uzun süren işlemlerde önce interaction.deferReply() çağırın; aksi halde 3 saniyelik etkileşim zaman aşımına takılırsınız.
  • Genel rate limit'e takılırsanız rateLimited olayını dinleyerek loglayabilir ve istek hacminizi düşürebilirsiniz.

Spam'a karşı ek önlemler

Cooldown ilk savunma hattıdır; agresif kötüye kullanıma karşı şu katmanları ekleyin:

  • Kademeli ceza: Cooldown'a tekrar tekrar takılan kullanıcının bekleme süresini geçici olarak artırın.
  • İzleme listesi: Belirli bir eşik üstünde komut deneyen kullanıcıyı kısa süre yok sayın (basit bir hız sınırlayıcı).
  • İzin kontrolü: Yöneticileri cooldown'dan muaf tutmak için interaction.memberPermissions kontrolü ekleyin.
  • Kalıcı saklama: Ödül/ekonomi komutlarında cooldown'u Redis veya veritabanında tutun ki bot yeniden başladığında suistimal edilmesin.

Sık Sorulan Sorular

Cooldown verilerini bellekte tutmak güvenli mi?

Küçük ve orta ölçekli botlar için bellek (Collection/Map) yeterli ve hızlıdır. Ancak bot her yeniden başladığında sıfırlanır. Çekiliş, ödül veya ekonomi gibi suistimale açık komutlarda cooldown'u Redis veya bir veritabanında kalıcı saklamanızı öneririm.

discord.js rate limit'leri benim için hallediyorsa neden ayrıca cooldown yazayım?

İkisi farklı amaca hizmet eder. discord.js'in REST katmanı botun Discord'a gönderdiği istekleri düzenler. Sizin cooldown'unuz ise kullanıcıların botu ne sıklıkta tetikleyebileceğini kontrol eder; mantık spam'ı, kaynak tüketimini ve oyun mekaniği suistimalini engeller.

discord.py için de aynı mantık geçerli mi?

Evet, prensip aynıdır: son kullanım zamanını saklayıp farkı kontrol edersiniz. discord.py'de ayrıca yerleşik @commands.cooldown dekoratörü ve BucketType seçenekleri vardır; bu da kullanıcı/sunucu/kanal bazlı cooldown'u tek satırda tanımlamanızı sağlar.

Botunuz spam altında mı eziliyor? Komut cooldown'ları, rate limit yönetimi ve kötüye kullanıma dayanıklı bir mimari ile botunuzu sağlamlaştırmanıza yardımcı olabilirim. Benimle iletişime geçin ve projenizi konuşalım.

Bu kategorideki tüm yazılar →

Devamı için