Asynchrony in Python. How to receive requests in a Python Telegram bot and at the same time perform another function

Issue

This Content is from Stack Overflow. Question asked by Tomas Angelo

I am coding telegram-bot, using Flask and asyncio. And I have a function for receiving and processing requests – get_messages(), and test function – sleep_func(), which will sleep for a while(20 seconds), but get_messages() will be working at this moment, when sleep_func() is sleeping. After 20 seconds sleep_func() wakes up, prints some text, but doesn’t finish the get_messages(). So, I want to implement asynchrony. I tried to do this, using asyncio.create_task, that worked, but only for one request(see at the comments in get_messages()). Now I tried another way, but it gives me this error:

ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-7' coro=<get_messages() done, defined at D:Python_LabsFilmMarketBotfm_bot.py:31> exception=RuntimeError('Timeout context manager should be used inside a task')>
Traceback (most recent call last):
  File "D:Python_LabsFilmMarketBotfm_bot.py", line 37, in get_messages
    await message(bot)
  File "D:Python_LabsFilmMarketBotbot_filesmessage_handling.py", line 14, in message
    await commands(bot, chat_id)
  File "D:Python_LabsFilmMarketBotbot_filesmessagesbot_commandscommands.py", line 11, in commands
    await start(bot, chat_id)
  File "D:Python_LabsFilmMarketBotbot_filesmessagesbot_commandscommands_methods.py", line 11, in start
    await bot.send_message(chat_id, f"Hello, {first_name}!")
  File "D:Python_LabsFM_Bot_testvenvlibsite-packagesaiogrambotbot.py", line 339, in send_message
    result = await self.request(api.Methods.SEND_MESSAGE, payload)
  File "D:Python_LabsFM_Bot_testvenvlibsite-packagesaiogrambotbase.py", line 231, in request
    return await api.make_request(await self.get_session(), self.server, self.__token, method, data, files,
  File "D:Python_LabsFM_Bot_testvenvlibsite-packagesaiogrambotapi.py", line 139, in make_request
    async with session.post(url, data=req, **kwargs) as response:
  File "D:Python_LabsFM_Bot_testvenvlibsite-packagesaiohttpclient.py", line 1138, in __aenter__
    self._resp = await self._coro
  File "D:Python_LabsFM_Bot_testvenvlibsite-packagesaiohttpclient.py", line 466, in _request
    with timer:
  File "D:Python_LabsFM_Bot_testvenvlibsite-packagesaiohttphelpers.py", line 701, in __enter__
    raise RuntimeError(
RuntimeError: Timeout context manager should be used inside a task

This is my fm_bot.py:

# бібліотека request для отримання запитів(повідомлень), які надходять на Flask-сервер від Телеграм-серверу і Stripe
from flask import Flask, request
import logging
from aiogram import Bot, Dispatcher
from threading import Thread
# from dotenv import load_dotenv
from time import sleep
import asyncio
import time

from bot_files.models import db, Users, Films, Purchases
from bot_files.message_handling import message, callback_query, object, other_messages
# from bot_files.other import technical_works
from bot_files.chat_member import delete_user
from bot_files.stripe import create_stripe_webhook
from bot_files.objects.stripe_requests_files.purchases import add_purchase
from bot_files.config import *

logging.basicConfig(level=logging.INFO)

bot = Bot(token=bot_token)
dp = Dispatcher(bot)

app = Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = db_url
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
db.init_app(app)


async def get_messages():
    print("Flag")
    print(request.json)
    message_type = list(request.json.keys())[1]

    if message_type == 'message':
        await message(bot)

    elif message_type == 'callback_query':
        await callback_query(bot, payment_token, stripe_token)

    elif message_type == 'my_chat_member':
        chat_id = request.json["my_chat_member"]["chat"]["id"]
        if request.json["my_chat_member"]["new_chat_member"]["status"] == "kicked":
            await delete_user(chat_id)

    elif message_type == 'object':
        await object(bot)

    elif message_type == 'pre_checkout_query':
        # Номер карти - 4242 4242 4242 4242
        chat_id = request.json["pre_checkout_query"]["from"]["id"]
        await add_purchase(bot, chat_id)
        pre_checkout_query_id = request.json["pre_checkout_query"]["id"]
        await bot.answer_pre_checkout_query(pre_checkout_query_id, True)

    # else:
    # await other_messages(bot)

    return {"get_messages is ok": True}


async def sleep_func():
    await asyncio.sleep(20)
    print("Hello!")


@app.route('/' + bot_token, methods=['POST'])
async def asynchrony():
    #start_time = time.time()
    #get_messages_task = asyncio.create_task(get_messages())
    #sleep_task1 = asyncio.create_task(sleep_func())
    #sleep_task2 = asyncio.create_task(sleep_func())
    #await asyncio.wait([get_messages_task, sleep_task1])
    #print(time.time() - start_time)
    get_messages_task = asyncio.create_task(get_messages())
    await asyncio.wait([get_messages_task])
    #await get_messages()

    return {"asynchrony is ok": True}


@app.route('/')
async def webhook():
    await bot.delete_webhook()
    await bot.set_webhook(url=app_url)
    # chat_id = None
    await create_stripe_webhook(app_url, payment_token)

    # await test_users()
    # await test_films()
    # await test_purchases()
    # await test_discounts()
    # while True:
    # time_now = datetime.datetime.now()
    # if datetime.date.today().isoweekday() == 4:
    # await technical_works(bot)

    sleep_task = asyncio.create_task(sleep_func())
    await asyncio.wait([sleep_task])

    return '!', 200


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5000)))

I will be very appreciative for you help!



Solution

This question is not yet answered, be the first one who answer using the comment. Later the confirmed answer will be published as the solution.

This Question and Answer are collected from stackoverflow and tested by JTuto community, is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?