Jonah Alexander
Jonah Alexander

Reputation: 51

My discord.py bot running on heroku keeps stopping

I have a very basic discord.py bot hosted on heroku. Its only function is to send a message from a list of possible messages every 24 hours. It always sends the first message and then stops. I can't find any errors in the code, and when I lower the timings and test it both running on my computer and running in heroku, it works fine.

It's all on one python file, with a few required files for heroku and the two text documents for messages.

Here is the main script:

import discord
import time
import random as rng

clnt = discord.Client()
ch = 0 #channel id
cnt = 0 #amount of minutes on timer
lp = True #i think this is just a leftover variable from another version, i can't find anywhere i used it


@clnt.event
async def on_ready():
    print('ready')


async def ph(): #function to send message
    global ch
    global lp

    qts = open('quotes.txt') #get messages
    qtz = qts.read().splitlines() #put messages in a list
    qts.close() #close file
    
    #if message file is empty, get the list from a backup file and put them into the first file, reseting the messages
    if not qtz:  
        qts2 = open('quoteslog.txt') 
        qtz2 = qts2.read().splitlines()
        qts2.close()

        with open('quotes.txt', 'w') as f:
            for i in qtz2:
                f.write("%s\n" % i)
            f.close()

        qts = open('quotes.txt')
        qtz = qts.read().splitlines()
        qts.close()

    #get random message from list
    x = rng.randint(1, len(qtz))
    x2 = x - 1
    y = qtz[x2]
    qtz.pop(x2)

    open('quotes.txt', 'w').close() #clear the list

    #rewrite the same file without the message sent
    with open('quotes.txt', 'w') as f:
        for i in qtz:
            f.write("%s\n" % i)
        f.close()
    
    #used for messages with new lines
    if y == 'ph1':
        await ch.send("this is for one of the messages, it has new lines so it can't be re-inserted into a txt file")
        await timer()

    elif y == 'ph2':
        await ch.send('same here')
        await timer()

    else:
        #send message to channel and restart the timer
        await ch.send(y)
        await timer()


@clnt.event
async def on_message(m):
    if m.author == clnt.user:
        return

    global ch

    if m.content.startswith('send here'):
        ch = clnt.get_channel(m.channel.id)
        await m.channel.send('ok')

    elif m.content.startswith('start'):
        await timer()


async def timer():  #loops every 60 seconds, 1440 times, or 24hrs
    global lp
    while lp:
        global cnt
        time.sleep(60)
        cnt += 1
        if cnt == 1440:
            cnt = 0 #reset timer and send message
            await ph() 


clnt.run('the discord bot id')

Yes, I know the code is probably garbage formatting-wise, but as far as I can tell it should be working and it isn't. I'm not even sure if it's a code error, could also be a heroku problem, but I have no idea.

If anyone has anything that could possibly help that would be greatly appreciated!

Upvotes: 0

Views: 580

Answers (1)

Jenny
Jenny

Reputation: 661

I recommend you use the Bot and Cog classes, it will be much more efficient, they are provided in discord.py, and have decorators to define a looping function. They are in the discord.ext.commands part of the module. You can do:

from discord.ext import commands, tasks

I just answered on another post with an example of a cog and a looping function, you'll find it here. Here is the same structure adapted to your case:

# LoopCog.py
from discord.ext import commands, tasks
import random

class LoopCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.test_loop.change_interval(minutes = self.bot.cnt)

    @commands.Cog.listener("on_ready")
    async def on_ready(self):
        self.test_loop.start()

    @tasks.loop(hours=24)
    async def test_loop(self):
        # insert your ph function contents here
        # access the channel id via self.bot.ch

def setup(bot):
    bot.add_cog(LoopCog(bot))
# main.py
from discord.ext import commands

bot = commands.Bot(command_prefix = "!")
bot.ch = 0 
bot.cnt = 0
bot.load_extension("LoopCog")

@bot.event
async def on_ready():
    print("ready")

bot.run(token, reconnect = True)

I suggest you go watch some tutorials. Using the Client class for a Bot is not the right way to go, you will have to program everything that is already in Bot if you keep going with Client.

You'll find the API documentation here for Bot, Cog, and tasks

Concerning heroku, it will unfortunately restart your bot every 24h, unless you go for a paying professional offer which includes 24/7 runtime. It will also put your program in sleep mode if it doesn't get any request within 30 min.

Upvotes: 3

Related Questions