skip to Main Content

Simple example

import asyncio
import logging
from aiogram import Bot, Dispatcher, types


logging.basicConfig(level=logging.INFO)
token = 'token'

bot = Bot(token=token)
dp = Dispatcher(bot=bot)
@dp.callback_query_handler(text='stoploop')
async def stop_loop(query: types.CallbackQuery):
    #  TODO how to stop test loop?

    await query.message.edit_text('stop')


@dp.callback_query_handler(text='test')
async def start_loop(query: types.CallbackQuery):
    a = 100
    while True:
        a -= 1
        markup = types.InlineKeyboardMarkup()
        markup.add(types.InlineKeyboardButton('<<<Stop And Back To Home', callback_data='stoploop'))
        await query.message.edit_text(str(a),reply_markup=markup)
        await asyncio.sleep(1)


@dp.message_handler(commands='start')
async def start_cmd_handler(message: types.Message):
    markup = types.InlineKeyboardMarkup()
    markup.add(
        types.InlineKeyboardButton('start loop', callback_data='test')
    )
    await message.reply('test', reply_markup=markup)


async def main():
    try:
        await dp.start_polling()
    finally:
        await bot.close()


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

When I click start_loop, the tg message box on my page starts to display a countdown. When I click stop, how can I stop the previous countdown?
I use id(query) to confirm that the query instance sent twice is not the same. After I execute the stop_loop function, start_loop will still execute and change the content of the message.
Can someone tell me how to stop it?

2

Answers


  1. Chosen as BEST ANSWER

    I used redis to solve it, but I don't know if this is the most appropriate way. If there is a more suitable way, please let me know


  2. To manage your loop you should take it outside the handlers and just get in from any storage (dict is used for example).

    Basic example of the loop

    loops = {}
    
    
    class Loop:
        def __init__(self, user_id):
            self.user_id = user_id
            self._active = False
            self._stopped = True
            loops[self.user_id] = self
        
        @classmethod
        def get_loop(cls, user_id):
            return loops.get(user_id, cls(user_id))
    
        @property
        def is_running(self):
            return not self._stopped
            
        async def start(self):
            self._active = True
            asyncio.create_task(self._run_loop())
            
        async def _run_loop(self):
            while self._active:
                await bot.send_message(self.user_id, 'loop is running')
                await asyncio.sleep(5)
            self._stopped = True
        
        async def stop(self):
            self._active = False
            while not self._stopped:
                await asyncio.sleep(1)
    

    So then:

    @dp.callback_query_handler(text='start')
    async def start_loop(query: CallbackQuery):
        user = query.from_user
        loop = Loop.get_loop(user.id)
        
        if loop.is_running:
            return await query.answer('Loop is already running')
        
        loop.start()
        await query.answer('Started!')
    
    
    @dp.callback_query_handler(text='stop')
    async def stop_loop(query: CallbackQuery):
        user = query.from_user
        loop = Loop.get_loop(user.id)
        await query.answer('Stopping...')
        await loop.stop()
        await bot.send_message(user.id, 'Loop successfully stopped.')
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search