Как настроить aioscheduler для работы с aiogram версии 3?

Пожалуйста, помогите мне разобраться с кодом ниже. Является ли он правильным и достаточно эффективным для выполнения своей задачи? В частности, хочу узнать о работе функции `dejur` и механизме планирования с использованием `aioschedule`. Вот код:

<pre><code class="python">import asyncio
import logging
import sys
import time
import aioschedule
import asyncio

from datetime import datetime

from aiogram import Bot, Dispatcher, types, html
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart
from aiogram.types import Message


TOKEN = ""
bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
parse = True
spisok = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15]
n = int()
prevweekday = int()
skipper = True

dp = Dispatcher()


async def weekday():
    now = datetime.now()
    current_weekday = now.weekday()
    return current_weekday


@dp.message(CommandStart())
async def dejur(message: Message):
    print(1)
    global n, skipper
    if weekday():
        await bot.send_message(chat_id=1108995102, text=f"Дежурные: {spisok[n]}")
        if skipper == True:
            if n != 14:
                n = n + 1
            else:
                n = 0
            return n
        else:
            skipper = True
            return skipper


async def scheduler():
    # aioschedule.every().day.at("12:00").do(dejur)
    aioschedule.every().minute.do(dejur)
    while True:
        await aioschedule.run_pending()
        await asyncio.sleep(1)


async def on_startup(_):
    asyncio.create_task(scheduler())


async def main():
    logging.basicConfig(level=logging.INFO)
    bot = Bot(token=TOKEN, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
    await dp.start_polling(bot)


if __name__ == "__main__":
    asyncio.run(main())</code></pre>
  • 16 сентября 2024 г. 16:23
Ответы на вопрос 2
Ваш код имеет несколько нюансов, которые следует исправить для корректной работы с `aiogram` версии 3 и `aioschedule`. Давайте по порядку разберем ваш код и предложим исправления.

### Основные проблемы:

1. **Функция `weekday`:** Хотя вы определили функцию `weekday`, она никогда не вызывается. Вместо этого вы используете ее в условии прямо в `if weekday():`, но эта конструкция ожидает булевое значение, тогда как функция возвращает целое число. Вместо этого вам нужно вызвать функцию и сравнить ее результат с нужным значением.

2. **Функция `dejur`:** Обратите внимание, что `dejur` вызывается по расписанию и `async def` функции не может возвращать значения, пока это не обрабатывается должным образом. Вам нужно изменить её так, чтобы она выполняла задуманное действие (например, отправку сообщения), а не пыталась возвращать значения.

3. **Отсутствие передачи параметров:** В функции `dejur` используете глобальные переменные, что может привести к неправильному поведению, если функция будет запускаться несколько раз.

4. **Параметр `TOKEN`:** Замените `TOKEN` на актуальный токен вашего бота.

### Предложенные исправления:

Вот исправленный вариант вашего кода:

```python
import asyncio
import logging
import aioschedule
from datetime import datetime
from aiogram import Bot, Dispatcher, types
from aiogram.enums import ParseMode
from aiogram.filters import CommandStart

TOKEN = "YOUR_BOT_TOKEN"  # укажите ваш токен
bot = Bot(token=TOKEN, parse_mode=ParseMode.HTML)
dp = Dispatcher()

spisok = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
n = 0  # Начальное значение для индекса
skipper = True

async def weekday():
    return datetime.now().weekday()

@dp.message(CommandStart())
async def start_command(message: types.Message):
    await message.answer("Вы запустили бота!")

async def dejur():
    global n, skipper
    current_weekday = await weekday()  # Получаем текущий день недели
    if current_weekday < len(spisok):  # Проверяем индекс
        await bot.send_message(chat_id=1108995102, text=f"Дежурные: {spisok[n]}")
        
        if skipper:
            n = (n + 1) % len(spisok)  # Увеличиваем n, циклически
            skipper = True
        else:
            skipper = True

async def scheduler():
    aioschedule.every().minute.do(dejur)  # Периодически выполняем dejur
    while True:
        await aioschedule.run_pending()
        await asyncio.sleep(1)

async def on_startup(_):
    asyncio.create_task(scheduler())

async def main():
    logging.basicConfig(level=logging.INFO)
    await dp.start_polling(bot, skip_updates=True)

if __name__ == "__main__":
    asyncio.run(main())
```

### Пояснения к изменениям:

- **Коррекция работы с `weekday`:** Теперь функция правильно возвращает текущий день недели, который далее используется для проверки.
  
- **Переменная `n`:** Переменная `n` теперь увеличивается циклически. Если доходит до конца списка `spisok`, она сбрасывается на 0.

- **Удален лишний импорт:** Удален лишний импорт `sys` и `time`, которые не использовались.

- **Простота использования:** Вызов функции `dejur` выполняет все необходимые действия и не пытается возвращать значения. 

- **Убедитесь, что у вас установлен `aiogram` 3.x и `aioschedule`.**

Попробуйте запустить исправленный код с вашим токеном, и он должен работать корректно.
@dp.message(CommandStart())  # обработчик события!
async def dejur(message: Message):
    ...

    aioschedule.every().minute.do(dejur)  # планируем вызов функции

Запомни раз и навсегда - никогда не вызывай обработчики событий напрямую.
Если тебе нужно реализовать одну и ту же функциональность и в обработчике, и где-то ещё - вынеси эту функциональность в отдельную подпрограмму, и уже её вызывай и в обработчике, и в других местах.
В твоём случае можно сделать что-то типа такого:
async def send_duty_list(chat: int):
    print(1)
    global n,skipper
    if weekday():
        await bot.send_message(chat, text=f"Дежурные: {spisok[n]}")
        if skipper == True:
            if n!=14:
                n = n+1
            else:
                n=0
            return n
        else:
            skipper = True
            return skipper

@dp.message(CommandStart())
async def dejur(message: Message):
    await send_duty_list(message.chat.id)


async def scheduler():
    aioschedule.every().minute.do(send_duty_list, chat=1108995102)
    while True:
        await aioschedule.run_pending()
        await asyncio.sleep(1)
Похожие вопросы