I'm making a discord.js scheduling bot. I am using node-schedule for this. It's not throwing any errors but it's still not sending a message. What am I doing wrong, and how do I get rid of this issue? (thank you in advance)
My code is:
const Discord = require('discord.js');
const client = new Discord.Client();
const schedule = require('node-schedule');
client.once('ready', () => {
console.log('Ready!');
});
client.login('TOKEN IS HERE');
const rule = new schedule.RecurrenceRule();
rule.tz = 'EDT';
client.on('message', message => {
if (message.content === '!schedule 9pm meeting') {
message.channel.send('Alright. I will announce it for you, friend! :smiley:');
const job = schedule.scheduleJob('00 21 * * *', function () {
client.channels.cache.get("channel id is here").send("This is a test message. Does it work?");
});
}
});
You can't run the schedule.scheduleJob
from inside the client.on
function and expect the message to still exist. Discord API expects a response to a webhook within a specific time before it times out.
Also, if the bot runs on a cloud service, the node it runs on might be restarting once in a while, which messes up in-memory data like attaching cron jobs in node-schedule
.
You should probably get scheduled time by the user and persist the data in some sort of database. You should use database read\writes in order to save the data between your cloud provider restarts (unless you have a paid subscription).
Since you can potentialy have thousands of scheduled meetings, it's better in your case to check for meetings withing a certain interval and send all the reminders at the same time.
Let's say a user can't give us a time more specific than a certain minute. Then we can check for reminders every minute, knowing we'll inform users before the meeting starts.
// Run checkForReminders every 60 seconds to scan DB for outstanding reminders
setInterval(checkForReminders, 60000);
// Parse reminder request, save to DB, DM confirmation to user
client.on('message', (msg) => {
createNewReminder(msg);
});
const createNewReminder = (msg) => {
const formattedMessage = formatMessage(msg)
// If message isn't a remindme command, cease function execution
if (!formattedMessage.startsWith('!remindme')) {
return
}
// Determine if message contains a number to assign to intervalInteger
checkForNumbersInMessage(formattedMessage)
// Final format for message to be sent at reminderTime
const messageToDeliverToUser = formattedMessage.replace('!remindme', '')
// Set integer and verb values for moment.add() parameters
const intervalInteger = parseInt(checkForNumbersInMessage(formattedMessage))
const intervalVerb = setIntervalVerb(formattedMessage)
// Format time to send reminder to UTC timezone
const reminderTime = moment().utc().add(intervalInteger, intervalVerb).format('YYYY-MM-DD HH:mm:ss')
// Save reminder to DB
saveNewReminder(msg.author.id, msg.author.username, messageToDeliverToUser, reminderTime)
// Send embedded message to author & notify author in channel of remindertime request
const embed = createEmbed(messageToDeliverToUser, reminderTime)
msg.author.send(embed)
msg.channel.send(`${msg.author} - A reminder confirmation has been sent to your DMs. I will DM you again at the requested reminder time`)
}
In order to send a message later, save either the userId
or guildId
to the database, then, retrieve the user or guild from the discord client, and send the message.
const checkForReminders = () => {
db.serialize(() => {
// Select all messages older than the current dateTime
db.each("SELECT id, reminderTime, userID, message FROM reminders WHERE reminderTime < DATETIME()", (error, row) => {
if (error || !row) {
return console.log('Error or no row found')
}
// If reminders are found, fetch userIDs, then send the requested reminder through DM
client.users.fetch(row.userID).then((user) => {
user.send(`Hi, you asked to be reminded "${row.message}" - That's right now!`).catch(console.error)
console.log(`Message delivered: ${row.message}`)
console.log(`Message deleted successfully`)
// Delete message after DMing to user
db.run("DELETE FROM reminders WHERE id = ?", [row.id])
console.log('Message sent and removed successfully')
})
})
})
}
Code examples where taken from NathanDennis/discord-reminder-bot. check out the repository for a complete example. He comments on his code so it's easy to understand.