Bir topluluk botunda en çok istenen özelliklerden biri discord zamanlanmış mesaj sistemidir: her gün belirli bir saatte günlük duyuru atan, hafta sonu etkinlik hatırlatması yapan ya da gece yarısı "iyi geceler" mesajı gönderen bir bot. Bu rehberde discord.js ve node-cron kullanarak, belirli saatte otomatik mesaj gönderen sağlam bir yapı kuracağız; saat dilimi, kalıcı saklama ve sık yapılan hataları da tek tek ele alacağız.
Yaklaşım: neden node-cron?
Sabit bir saatte mesaj göndermek için akla ilk gelen setTimeout veya setInterval olur, ama bunlar "her 24 saatte bir" gibi göreli aralıklarla çalışır; "her gün saat 09:00'da" gibi takvim tabanlı bir kuralı ifade edemezler. node-cron tam burada devreye girer: Linux'taki cron sözdizimini Node.js içinde çalıştırır, böylece "her gün, her pazartesi, ayın 1'inde" gibi kuralları tek satırla tanımlarsınız.
- Takvim tabanlı: Mutlak saat/gün belirtirsiniz, geçen süreyi siz hesaplamazsınız.
- Saat dilimi desteği: Sunucunuz hangi bölgede olursa olsun, mesajı doğru yerel saatte attırabilirsiniz.
- Hafif: Harici servise veya veritabanına bağımlı değildir; bot süreci açık olduğu sürece çalışır.
Botunuz 7/24 açık değilse, zamanlama anında bot çevrimdışıyken mesaj atlanır. Bu yüzden zamanlanmış görevler için botu bir VPS'te PM2 ile veya kesintisiz bir hosting'te çalıştırmak şarttır.
Kurulum ve cron sözdizimi
Önce paketi kuralım:
npm install discord.js node-cron
node-cron standart cron sözdizimini kullanır; ek olarak başa isteğe bağlı bir saniye alanı koyabilirsiniz. Alanların sırası şöyledir:
# ┌──────────── saniye (0-59, opsiyonel)
# │ ┌────────── dakika (0-59)
# │ │ ┌──────── saat (0-23)
# │ │ │ ┌────── ayın günü (1-31)
# │ │ │ │ ┌──── ay (1-12)
# │ │ │ │ │ ┌── haftanın günü (0-7, 0 ve 7 = Pazar)
# │ │ │ │ │ │
# * * * * * *
Birkaç pratik örnek:
0 9 * * *→ her gün saat 09:0030 18 * * 5→ her cuma 18:300 */6 * * *→ her 6 saatte bir (00:00, 06:00, 12:00, 18:00)0 0 1 * *→ her ayın 1'inde gece yarısı
İfadenizin geçerli olup olmadığını cron.validate('0 9 * * *') ile kontrol edebilirsiniz; true/false döner.
discord.js ile belirli saatte mesaj gönderme
Asıl mantık iki parçadan oluşur: botu hazır hale getirmek ve ClientReady olayında cron görevlerini başlatmak. Görev tetiklendiğinde hedef kanalı çekip send() ile mesajı atarız:
const { Client, GatewayIntentBits } = require('discord.js');
const cron = require('node-cron');
const client = new Client({
intents: [GatewayIntentBits.Guilds],
});
const CHANNEL_ID = '123456789012345678';
client.once('clientReady', () => {
console.log(`Giris yapildi: ${client.user.tag}`);
// Her gun saat 09:00'da gunluk mesaj
cron.schedule('0 9 * * *', async () => {
try {
const channel = await client.channels.fetch(CHANNEL_ID);
if (channel?.isTextBased()) {
await channel.send('Gunaydin! Bugun harika bir gun olsun. ☀️');
}
} catch (err) {
console.error('Zamanlanmis mesaj gonderilemedi:', err);
}
}, {
timezone: 'Europe/Istanbul',
});
});
client.login(process.env.DISCORD_TOKEN);
Önemli noktalar:
client.channels.fetch(), kanal önbellekte olmasa bile API'den getirir; bu yüzdencache.get()'ten daha güvenilirdir.isTextBased()kontrolü, kanalın gerçekten mesaj alabileceğini doğrular ve tip hatalarını önler.try/catchşart: kanal silinmiş veya botun yetkisi alınmışsa, hata botu çökertmesin.
Yalnızca mesaj göndermek için GatewayIntentBits.Guilds yeterlidir; MessageContent gibi ayrıcalıklı intent'lere ihtiyaç yoktur.
Saat dilimi: en sık yapılan hata
Zamanlanmış mesajlarda kullanıcıların en çok şaşırdığı nokta, mesajın "yanlış saatte" gelmesidir. Sebep neredeyse her zaman saat dilimidir. node-cron, timezone seçeneğini vermezseniz sunucunun yerel saatini kullanır. Bir VPS çoğunlukla UTC'de çalışır, dolayısıyla 0 9 * * * ifadesi Türkiye'de 12:00'a denk gelebilir.
Çözüm her zaman timezone seçeneğini açıkça belirtmektir. Değer, IANA saat dilimi adı olmalıdır: Europe/Istanbul, Europe/Paris, America/New_York gibi. Bu yöntemin güzel yanı, yaz/kış saati geçişlerini de otomatik yönetmesidir; siz saati değiştirmezsiniz, node-cron doğru yerel ana göre tetikler.
Mesajları kalıcı saklamak ve dinamik zamanlama
Yukarıdaki örnek mesajları koda gömer. Gerçek bir botta, yöneticilerin slash komutuyla yeni zamanlanmış mesaj eklemesini istersiniz. Bu durumda zamanlamaları bir veritabanında (SQLite, MongoDB vb.) saklamanız gerekir, çünkü bot her yeniden başladığında bellekteki görevler kaybolur. Genel akış şöyledir:
- Yönetici bir komutla kanal, saat (cron ifadesi) ve metin girer; kayıt veritabanına yazılır.
- Bot açılırken (
clientReady) tüm kayıtlar okunur ve her biri için bircron.schedulegörevi oluşturulur. - Görevleri bir
Map'te kayıt kimliğine göre saklarsınız ki sonradan iptal edebilesiniz.
Bir görevi durdurmak ve yeniden başlatmak için node-cron'un döndürdüğü nesneyi kullanırsınız:
const tasks = new Map();
function scheduleMessage(record) {
const task = cron.schedule(record.cronExpr, async () => {
const channel = await client.channels.fetch(record.channelId);
if (channel?.isTextBased()) await channel.send(record.text);
}, { timezone: record.timezone });
tasks.set(record.id, task);
}
// Bir zamanlamayi iptal etmek:
function cancelMessage(id) {
const task = tasks.get(id);
if (task) {
task.stop();
tasks.delete(id);
}
}
Bu yapı sayesinde "/zamanla" komutuyla yeni mesaj ekleyebilir, "/iptal" komutuyla mevcut bir zamanlamayı durdurabilirsiniz. Tek seferlik hatırlatmalar için cron yerine, tek bir tarih/saatte tetiklenen node-schedule kütüphanesi daha uygundur; tekrar eden mesajlar için node-cron idealdir.
Sık Sorulan Sorular
Bot kapalıyken kaçırılan mesajlar ne olur?
node-cron yalnızca süreç çalışırken tetiklenir; bot çevrimdışıyken gelen zamanlama atlanır ve telafi edilmez. Bu yüzden zamanlanmış görevler için botu PM2 veya systemd ile 7/24 açık tutmak gerekir. Kaçırılanları telafi etmek istiyorsanız, son çalışma zamanını veritabanına yazıp açılışta kontrol eden ek bir mantık yazmanız gerekir.
node-cron ile node-schedule arasındaki fark nedir?
node-cron, cron sözdizimiyle tekrar eden görevler için tasarlanmıştır ("her gün 09:00"). node-schedule ise belirli bir Date nesnesinde tek seferlik tetikleme yapabilir ("17 Ağustos 14:30'da bir kez"), bu yüzden tekil hatırlatmalar için daha uygundur. İkisi de saat dilimini destekler.
Saniyede bir gibi çok sık görevler mantıklı mı?
Mümkündür ama nadiren gerekir. Çok sık mesaj göndermek Discord'un rate limit'lerine takılmanıza yol açar ve kanalı kirletir. Zamanlanmış mesajlar için dakika veya saat ölçeği yeterlidir; saniye alanını ancak gerçek bir ihtiyaç varsa kullanın.
Botunuza güvenilir bir zamanlama sistemi mi lazım? Saat dilimi doğru ayarlanmış, veritabanı destekli ve yeniden başlatmaya dayanıklı bir zamanlanmış mesaj altyapısını sizin için kurabilirim. Benimle iletişime geçin, projenizi birlikte planlayalım.