Search code examples
pythonpython-asynciotelegrampython-telegram-bot

How to send a telegram message without blocking main thread


from telegram import Bot
import asyncio

TOKEN = "blah"
CHAT_ID = 1

async def send_message_async():
    message = "This is a test update from the bot!"
    bot = Bot(token=TOKEN)
    await bot.send_message(chat_id=CHAT_ID, text=message)
    print("Message sent successfully!")


async def main():

    print("Before sending message...")

    await send_message_async()

    print("After sending message...") # I don't want this to be blocked until the message is sent


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

I'm trying to send message without blocking whole thread, but I'm struggling to avoid it. Is there any way?

I am hoping to find a simpler API to above problem. Something like below

def send_message():
    # Sends message to user asynchonously without blocking the main thread
    pass

def main():
    # Main function
    send_message()

But it seems like, to call one async function, every other function should be converted into async function.


Solution

  • If you don't want to wait then don't use await but create_task()

    task = asyncio.create_task(send_message_async())
    

    You can use await task at the end of program to check if you may exit program
    or you have to wait for end of this task.

    # wait for end of task
    await task
    # or 
    result = await task
    

    You may also use if task.done(): to check it without blocking code.

    if task.done():
        result = await task
    else:
        # ...
    

    from telegram import Bot
    import asyncio
    
    TOKEN = "blah"
    CHAT_ID = 1
    
    async def send_message_async():
        print('starting send_message_async()')
        message = "This is a test update from the bot!"
        #bot = Bot(token=TOKEN)
        #await bot.send_message(chat_id=CHAT_ID, text=message)
        await asyncio.sleep(3)
        print("Message sent successfully!")
    
    async def main():
    
        print("Before sending message...")
    
        task = asyncio.create_task(send_message_async())
        #await send_message_async()
    
        print("After sending message...")
    
        await asyncio.sleep(6)
    
        print("End...")
    
        # wait for end of task (to makes sure it finished)
        await task
    
    if __name__ == "__main__":
        asyncio.run(main())
    

    Example with more print() to show that functions run at the same time.

    from telegram import Bot
    import asyncio
    
    TOKEN = "blah"
    CHAT_ID = 1
    
    async def send_message_async():
        print('starting send_message_async()')
        message = "This is a test update from the bot!"
        #bot = Bot(token=TOKEN)
        #await bot.send_message(chat_id=CHAT_ID, text=message)
        
        for i in range(10):
            print('sending', i)
            await asyncio.sleep(0.5)
            
        print("Message sent successfully!")
    
        return "It's done!"
    
    async def main():
    
        print("main: Before sending message...")
    
        task = asyncio.create_task(send_message_async())
        #await send_message_async()
        await asyncio.sleep(0.01)
        #print(dir(task)) # 
        
        print("main: After sending message...")
    
        for i in range(3):
            print('main', i)
            await asyncio.sleep(0.5)
    
        print("main: End")
    
        while not task.done():
            print('main: waiting for end of task')
            await asyncio.sleep(1)
    
        # wait for end of task
        #await task 
        result = await task  # if function use `return` to send result
        print('main: result:', result)
            
    if __name__ == "__main__":
        asyncio.run(main())
    

    Result:

    main: Before sending message...
    starting send_message_async()
    sending 0
    main: After sending message...
    main 0
    sending 1
    main 1
    sending 2
    main 2
    sending 3
    main: End
    main: waiting for end of task
    sending 4
    sending 5
    main: waiting for end of task
    sending 6
    sending 7
    main: waiting for end of task
    sending 8
    sending 9
    main: waiting for end of task
    Message sent successfully!
    main: result: It's done!