简体   繁体   中英

How do I schedule a function to run everyday at a specific time in discord.py?

I want the bot to run a defined function everyday. I did some research and then I was able to write this:

def job():
    print("task")
    
schedule.every().day.at("11:58").do(job)

while True:
    schedule.run_pending()
    time.sleep(1)

but this code is blocking all other functions so I did some more research from other stack overflow answers and then I was able to write this:

def job():
    print('hi task')

def threaded(func):
    job_thread = threading.Thread(target=func)
    job_thread.start()

if __name__=="__main__":

    schedule.every().day.at("12:06").do(threaded,job)      
    while True:
        schedule.run_pending()

unfortunately this too , blocks my entire code. I need something that doesn't block other parts of my code. How to do that?

You can use Tasks .

So let's say you want to upload a JSON file to a specific channel every day (24 hours) you will do something like this

    @tasks.loop(hours=24)
    async def upload_json_to_discord():
        channel_to_upload_to = client.get_channel(JSON_UPLOAD_CHANNEL_ID)
        try:
            await channel_to_upload_to.send(file=discord.File("id-list.json"))
            print("JSON file upload success")
        except Exception as e:
            print(f"Upload JSON failed: {e}")

and then you need to start the loop by using loop_func_name.start() so in this case:

upload_json_to_discord.start()

and so this will make the function run once every 24 hours

In case you are in a cog, you will have to use this in the __init__ function of the Cog's class

You can find detailed information on this in the documentation: https://discordpy.readthedocs.io/en/latest/ext/tasks/

I am late to the party but since this question doesn't have an answer i'll throw mine in.

I'll assume you need this for a discord py bot since this is in your tags. As @Zacky said, you should use Tasks .

A function with @tasks.loop(hours=24) decorator won't start exactly every 24 hours, but will be scheduled in 24 hours when the function ends . This means you can delay the execution until the time you want, and then let the flow of the function continue until the end. Once there, the function will wait 24 hours to be executed again and it will correspond to the time of the day you want (plus the execution time of the function, so be careful if you want very precise function execution)

Here's how I'd do it

def seconds_until(hours, minutes):
    given_time = datetime.time(hours, minutes)
    now = datetime.datetime.now()
    future_exec = datetime.datetime.combine(now, given_time)
    if (future_exec - now).days < 0:  # If we are past the execution, it will take place tomorrow
    future_exec = datetime.datetime.combine(now + datetime.timedelta(days=1), given_time) # days always >= 0

    return (future_exec - now).total_seconds()
    

@tasks.loop(hours=24)
async def job(self):
    await asyncio.sleep(seconds_until(11,58))  # Will stay here until your clock says 11:58
    print("See you in 24 hours from exactly now")

as @dan pointed out, this might fail if the part of the code after the wait is not instantaneous, therefore here is a better solution

def seconds_until(hours, minutes):
    given_time = datetime.time(hours, minutes)
    now = datetime.datetime.now()
    future_exec = datetime.datetime.combine(now, given_time)
    if (future_exec - now).days < 0:  # If we are past the execution, it will take place tomorrow
    future_exec = datetime.datetime.combine(now + datetime.timedelta(days=1), given_time) # days always >= 0

    return (future_exec - now).total_seconds()
    

async def my_job_forever(self):
    while True:  # Or change to self.is_running or some variable to control the task
        await asyncio.sleep(seconds_until(11,58))  # Will stay here until your clock says 11:58
        print("See you in 24 hours from exactly now")
        await asyncio.sleep(60)  # Practical solution to ensure that the print isn't spammed as long as it is 11:58

For future people facing the same problem, the above answers using Tasks are correct, but depending on the hosting service you are using there might be an easier solution.

A popular choice is Heroku , you can find multiple tutorials to setup your bot like this one .

Then you can use the Heroku Scheduler add-on: 在此处输入图片说明

to run your bot at a specified time :
在此处输入图片说明

and that's it, if you want to run a specific function in your bot you can specify arguments in the command and catch them in your code instead of just python bot.py like me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM