Seth Bowers
Seth Bowers

Reputation: 35

Discord.py Bot Takes too Long to Respond

Goal:

I'm developing a discord bot which scans a url every 5 seconds or so, checks for a specified change on that webpage, and will send a message in the discord channel if that change occurs. I've done this by sending the url to the bot using an if statement in on_message. The url is then passed to a tasks.loop() function, where it is scanned and processed in another function for the change.

Problem:

I'd like to be able to send a message in the discord channel which quickly ends the process taking place in the tasks.loop(), so that I can pass it a different url to scan using the on_message function. In its current form, it works-- just very slowly. From the time the cancel trigger is sent, it takes around 3 minutes to send the verification message that the process has been cancelled. I need to make this 5 seconds or less. For what its worth, the bot is kept running using replit and uptime robot, but I am sure that the long response time is not related to the frequency the repl is awoken by uptime robot.

Code:

My code is much more complex and riddled with obscurely named variables, so here is a much simpler snippet of code with the same general structure.

client = discord.Client()
channel = client.get_channel(CHANNEL_ID)

@tasks.loop()
async def myloop(website, dataframe):
    
    channel = client.get_channel(CHANNEL_ID)
    
    try:
        # iteratively scrape data from a website for
        # a predefined change in the dataframe
        if change = True:
            await channel.send(notification)
            
    except:
        pass


@client.event
async def on_message(message):
    
    channel = client.get_channel(CHANNEL_ID)
    msg = message.content
    
    if msg.startswith('track'):
        
        website = msg[6:]
        await channel.send('Now tracking '+str(website))
        myloop(website,df)

    if msg.starswith('stop'):
        
        myloop.cancel()
        await channel.send('Done tracking, awaiting orders.')

        

Attempted Solutions:

I have tried using some forms of threading, which I am very new to, and I haven't found a way to make it work any faster. Any suggestions or solutions would be greatly appreciated! I've been combing the web for help for quite some time now.

Upvotes: 0

Views: 1518

Answers (1)

wheelercj
wheelercj

Reputation: 137

Looks like you could use client.loop.create_task to create asyncio task objects, and their cancel method to immediately cancel those asyncio tasks at the right time, e.g.

import asyncio
from replit import db


_task = None


async def myloop():
    website = db['website']
    dataframe = db['dataframe']
    channel = client.get_channel(CHANNEL_ID)

    while not client.is_closed():
        await asyncio.sleep(5)
        try:
            # iteratively scrape data from a website for
            # a predefined change in the dataframe
            if change:
                await channel.send(notification)
        except:
            pass


@client.event
async def on_message(message):
    global _task  # This gives the function access to the variable that was already created above.
    msg = message.content
    
    if msg.startswith('track'):
        website = msg[6:]
        await message.channel.send('Now tracking '+str(website))
        db['website'] = website
        db['dataframe'] = df
        if _task is not None:
            _task.cancel()
        _task = client.loop.create_task(myloop())

    if msg.startswith('stop'):
        if _task is not None:
            _task.cancel()
            _task = None
            await message.channel.send('Done tracking, awaiting orders.')

The argument create_task takes is a coroutine that takes no arguments, so the website URL and dataframe need to be accessible to the function a different way (I'm not sure which way you would prefer or would be best; using replit's db is just an example).

With this approach, you should be able to use track again to change which website is being monitored without using stop in between.

More details in the docs:

Upvotes: 1

Related Questions