问题描述
我正在使用discord.py创建一个discord机器人,我需要每天在特定时间执行某些操作。我看到了这个答案:How to make a loop in discord.py rewrite?,到目前为止我一直在使用它。
当我将机器人托管在heroku免费计划上时,问题就开始了。 Heroku上的服务器每天至少重置一次,这会弄乱计时器,如该帖子中所示。
我还看到了schedule库。问题在于它似乎使用了无限循环。那不会阻止我在24小时内运行其他任何东西吗?除了每24小时发送一次消息外,该机器人还需要始终能够响应命令。
即使服务器重置,如何每天仍在特定时间执行操作?预先谢谢你!
解决方法
您可以编写一个函数,使其在其他线程上定期运行,并检查是否是发送消息的正确时机,例如以下示例:
from datetime import datetime
import threading
def checkTime():
# This function runs periodically every 1 second
threading.Timer(1,checkTime).start()
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
print("Current Time =",current_time)
if(current_time == '02:11:00'): # check if matches with the desired time
print('sending message')
checkTime()
,
您是否考虑过使用多线程来运行程序?您可能有一个线程在等待一天中所需的时间,而另一个正在运行程序的其余部分。 以下是一些文档可帮助您入门:documentation,Intro to Python Threading
,heroku免费计划是Linux。因此,cron可以让您在特定时间运行,而/etc/init.d/可以让您在启动时运行。了解您的操作系统是一件好事。
,我知道我迟到了,但这可能对未来的用户有帮助。
有一个名为 APScheduler
的库可用于通过设置 cron 作业来运行函数(也有其他方法代替 cron。Read more)。
一个小例子如下:
import discord
from discord.ext import commands
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
class Scheduler(commands.Cog):
"""Schedule commands."""
def __init__(self,bot):
self.bot = bot
# Initialize session
self.session = aiohttp.ClientSession()
# Scheduled events
async def schedule_func(self):
def schedule(self):
# Initialize scheduler
schedule_log = logging.getLogger("apscheduler")
schedule_log.setLevel(logging.WARNING)
job_defaults = {
"coalesce": True,"max_instances": 5,"misfire_grace_time": 15,"replace_existing": True,}
scheduler = AsyncIOScheduler(job_defaults = job_defaults,logger = schedule_log)
# Add jobs to scheduler
scheduler.add_job(self.schedule_func,CronTrigger.from_crontab("0 * * * *"))
# Every hour
并在我们的 main.py
文件中添加以下内容(显然是在导入 schedule_jobs.py
文件之后):
# Start scheduled commands
scheduler = schedule_jobs.Scheduler(bot).schedule()
scheduler.start()
,
您可以有一个无限循环并使用asyncio.sleep()函数。这使您可以从脚本中的任何位置处理命令,并且仍然等待时间。这是一个小例子:
import asyncio
while True:
await asyncio.sleep(60)
print(1)
@client.command()
async def command(ctx):
pass
每分钟脚本将打印1,并且只要有人执行该命令就会执行。