I'm making a schedule Discord.js bot, but it's not sending a message

1.9k Views Asked by At

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?");
    });
  }
});
1

There are 1 best solutions below

0
On BEST ANSWER

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.

Persisting the data

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).

Have a global cron job or interval

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);
});

New reminders handling

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`)
}

Send a message to a guild or user later

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.