Объединение двух ботов на discord py в одного

У меня есть два бота и две задачи для них. Я их не могу объеденить по одной причине. Есть две функции on_message и on_ready В функции on_ready реализован бесконечный цикл. Отправка сообщений утром и вечером А в функции on_message разные условия для сообщений По отдельности работает, вместе - нет. Я предполагаю, что это из за бесконечного цикла. То есть бесконечно проверяет время сейчас и нужное мне и поэтому не реагирует на сообщения, потому что занят проверкой времени. В этом ли проблема и если да, то как по другому реализовать функцию on_ready, чтобы она и функция on_message работала.

import discord
from datetime import datetime, time
import time

client = discord.Client()

@client.event
async def on_ready():
    channel = client.get_channel(id)
    while True:
        if str(datetime.now().hour) == '6':
            await channel.send(f"Доброе утро")
            time.sleep(4000)
        elif str(datetime.now().hour) == '20':
            await channel.send(f"Спокойной ночи")
            time.sleep(4000)

@client.event
async def on_message(message):
    if message.content == 'hi':
        await message.reply('hi')

Ответы (2 шт):

Автор решения: denisnumb

Самый простой вариант — вынести бесконечный цикл в отдельный поток. Для этого в asyncio предусмотрена специальная функция run_coroutine_threadsafe(func(), client.loop), которая первым аргументом принимает вызов функции, а вторым цикл событий, где нужно запустить эту функцию с сохранением основного потока.

Таким образом должно получиться что-то такое:

import asyncio
. . .

async def loop():
    channel = client.get_channel(id)
    while True:
        if str(datetime.now().hour) == '6':
            await channel.send(f"Доброе утро")
            time.sleep(4000)
        elif str(datetime.now().hour) == '20':
            await channel.send(f"Спокойной ночи")
            time.sleep(4000)

@client.event
async def on_ready():
    asyncio.run_coroutine_threadsafe(loop(), client.loop)
    # а далее уже остальные действия
    . . .

. . .
→ Ссылка
Автор решения: Daniil Loban

Можно подойти к задаче немного иначе, вынести бесконечный цикл из события и тем самым дополнительно подготовить код к дальнейшему расширению функционала. Пока кода не очень много возможность расширения его может казаться не проблемой, но если код изначально плохо спроектирован - то придется его переписывать или писать костыли, чтобы добавить функционал.

В python есть библиотека планировщик, которой можно задать точное время выполнения каких либо функций.

Таким образом код можно организовать примерно так:

import discord
from datetime import datetime, time
import time
import schedule

client = discord.Client()

@client.event
def on_ready():
    channel = client.get_channel(id)
    schedule.every().day.at("06:00").do(lambda: channel.send(f"Доброе утро"))
    schedule.every().day.at("20:00").do(lambda: channel.send(f"Спокойной ночи"))

@client.event
async def on_message(message):
    if message.content == 'hi':
        await message.reply('hi')  

while True:
    schedule.run_pending()
    # другие действия
    time.sleep(1)
→ Ссылка