0

I can't seem to understand why CTL+C is not working.

I think it's something I don't yet understand about the way async functions work and asyncio.sleep()

However, I have found this bug report which might be related as well as people using event loops with async functions in python. Also, there are questions like run async while loop independently but they don't really answer my question or provide insight.

async def set_maintain_countdown_message(countdown, message):
    try:
        countdown_message = await app.send_message(
            message.chat.id,
            await get_formated_countdown(countdown)
            )
        await asyncio.sleep(random.randint(4, 8))
        while countdown['state'] == 'active':
            await countdown_message.edit(
                await get_formated_countdown(countdown)
            )
            await asyncio.sleep(random.randint(4, 8))

    except FloodWait as e:
        await asyncio.sleep(e.x)
Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
Chris
  • 704
  • 1
  • 11
  • 32

1 Answers1

2

You can implement it using custom signal handlers.

Unfortunately asyncio by default doesn't work that way, and for a major reason: If you have multiple coroutines waiting at once, which one will it cancel?

Also, I will not go into how asyncio is implemented internally, which I answered on a different question, but the interpreter isn't actually sleeping at that line of code, so a KeyboardInterrupt won't be thrown there.

Creating a custom signal handler to handle SIGINT is probably what you're looking for.

Keep in mind - if you do not use asyncio.run() to run the code, you must make sure you shut down the coroutines (cancelling everything) gracefully using loop.shutdown_asyncgens().

Bharel
  • 23,672
  • 5
  • 40
  • 80
  • `which one will it cancel`, as a consumer of the library, I don't care. I just want the signal handling to work. So the library maintainers should implement it in a manner such that the signal bubbles up the synchronous code wrapping around the async code. If that means cancelling all of them, then so be it. – wheeler Feb 08 '23 at 05:50
  • @wheeler so you're saying that if you have 5 coroutines of different libraries you want a single library to cancel all of them by mistake including unrelated coroutines and everything else? – Bharel Feb 08 '23 at 15:54
  • What I want is for the program to make a best-effort attempt to cleanly and immediately quit. Whether or not it is a "mistake" for a library to cancel all tasks in order for the program to come to a halt is irrelevant--the only mistake being made here is a program not coming to a halt when Ctrl + C is pressed. – wheeler Feb 09 '23 at 00:16
  • That's what **you** @wheeler wish, and for that **you** should make a handler :-) Python throws KeyboardInterrupt in the current location. If it is in a function, people can catch it and revert it. It won't continue throwing, just as it won't throw it in 20 other coroutines. If someone catches it in a coroutine, then what? It's a behavior that is impossible to define or determine. That's where your wish goes into the picture, and as a programmer, that's your responsibility to program. – Bharel Feb 09 '23 at 05:49
  • @wheeler if you want, you can easily create a handle that `.cancel()`s all tasks, but be wary, as you will enter some places you probably wish you didn't, and plenty of bugs might pop up. – Bharel Feb 09 '23 at 05:52