pythonpython-asynciotelegrampython-multithreadingpy-telegram-bot-api

Telegram bot can't send a message from another thread, Request Timeout


I use async version of pyTelegramBotApi for a Telegram bot part. I use vk-api for a VK part (not sure if that matters).

I have a bot that monitors other social network (Vkontakte) and, on some occasions, calls a method that should make Telegram bot send me a message. Here is this method:

async def send_post(text, post_id) -> None:
    print("tg_bot.py.send_post()")

    msg_text = f"{text}\n\n[id={post_id}]"

    """Send the post."""
    await tg_bot.send_message(my_chat_id, text=msg_text, reply_markup=gen_markup())

When I try it, it gives me this error: ERROR: RequestTimeout::Request timeout. Request: method=get url=sendMessage params=<aiohttp.formdata.FormData object at 0x0000022B66B1F5D0> files=None request_timeout=300

I get this error only when I call send_post from the loop of receiving events from VK. When I use same tg_bot.send_message() method, for example, in response to command - it works perfectly. It's not connected to the markup or message text also, I tried changing these out of despair. Here's the VK loop in vkontakte.py, just in case:

def init():
    print("Starting VK Cycle")
    try:
        for event in longpoll.listen():
            print("There's a VK event")
            event_received = False
            while not event_received:
                print("Trying to receive it...")
                try:
                    if event.type == VkBotEventType.WALL_POST_NEW:
                        print("It's a new post on the wall")
                        post = event.object

                        if post.post_type == 'suggest':
                            print("The new post is a suggested post")
                            asyncio.run(tg_bot.send_post(text=post.text, post_id=post.id))

                    event_received = True
                except requests.exceptions.ReadTimeout as e:
                    print("ERROR: ReadTimeout. Waiting for 3 seconds and trying to reconnect")

                    log_file = open("cogparty.log", "a")
                    log_file.write(
                        f"\n\nvkontakte.py init() INNER try-catch error:\n\n{str(e)}\n\nTrying again in 3 seconds...")
                    log_file.close()

                    time.sleep(3)
    except Exception as e:
        print(f"ERROR: {type(e).__name__}::{str(e)}")

        log_file = open("cogparty.log", "a")
        log_file.write(f"\n\nvkontakte.py init() OUTER try-catch error:\n\n{str(e)}")
        log_file.close()

I've also read that it's important how you start the bot, so here's my setup:

async def main():
    vk_thread = threading.Thread(target=run_vk_loop)
    vk_thread.start()

    await tg_bot.init()

Then, in tg_bot.py, I have this:

async def init():
    print("Connecting to TG...")
    await tg_bot.infinity_polling()

I've also tried to set timeout parameter in infinity_polling to 30, 40, 50. No effect. The fun thing is - it worked before, for several days, and then crashed. Now it doesn't work from the beginning. I'm bad with both vkontakte and telegram bots, so my code is a mess, sorry. I would be very thankful if we can solve this together.


Solution

  • This is not a good answer, but it works. It seems that vk_api and pyTelegramBotApi use some common resource that's shared within a thread. Simply switching from threading to multiprocessing solves the problem.

    So, instead of this:

    async def main():
        vk_thread = threading.Thread(target=run_vk_loop)
        vk_thread.start()
    
        await tg_bot.init()
    

    I now use this:

    def main():
    
        vk_process = Process(target=run_vk_loop)
        vk_process.start()
    
        tg_process = Process(target=run_tg_loop)
        tg_process.start()