Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling interruption in async tasks #88927

Closed
ilianiliev mannequin opened this issue Jul 28, 2021 · 5 comments
Closed

Handling interruption in async tasks #88927

ilianiliev mannequin opened this issue Jul 28, 2021 · 5 comments
Labels
topic-asyncio type-bug An unexpected behavior, bug, or error

Comments

@ilianiliev
Copy link
Mannequin

ilianiliev mannequin commented Jul 28, 2021

BPO 44764
Nosy @IlianIliev

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2021-07-28.16:18:43.408>
labels = ['type-bug']
title = 'Handling interruption in async tasks'
updated_at = <Date 2021-07-28.16:18:54.865>
user = 'https://github.com/ilianiliev'

bugs.python.org fields:

activity = <Date 2021-07-28.16:18:54.865>
actor = 'ilian'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = []
creation = <Date 2021-07-28.16:18:43.408>
creator = 'ilian'
dependencies = []
files = []
hgrepos = ['407']
issue_num = 44764
keywords = []
message_count = 1.0
messages = ['398400']
nosy_count = 1.0
nosy_names = ['ilian']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'behavior'
url = 'https://bugs.python.org/issue44764'
versions = []

@ilianiliev
Copy link
Mannequin Author

ilianiliev mannequin commented Jul 28, 2021

The idea is to provide a way for graceful shutdown so that if an interruption occurs all async tasks are given a certain time to finish before we exit the process.

Please take a look at the provided example -> https://gist.github.com/IlianIliev/9aba04a74a4faddf0749533205d3b001

If the interruption happens during an await (if we use await asyncio.sleep(5)), all works correctly. The exception is raised to the root level and we do the graceful shutdown on line 37.

But if the interruption happens during a normal execution (time.sleep()) it is raised at the currently running line and this way breaks the function without any chances or recovery.
While time.sleep is not that widely used, the same problem occurs if we have any other long-running code e.g. iterating over a big list.

This was found while looking for a way to provide a graceful shutdown for the grpcio server -> grpc/grpc#26123

Is it possible to change the behaviour so the exception is raised on a higher level when sync tasks are executed in async context?

@ilianiliev ilianiliev mannequin added 3.9 only security fixes type-bug An unexpected behavior, bug, or error and removed 3.9 only security fixes labels Jul 28, 2021
@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
@gvanrossum
Copy link
Member

@IlianIliev

This issue was quite mysterious to me until I followed the link to grpc/grpc#26123. There (towards the end) it is implied that grpc has a feature called "graceful shutdown" which appears to be working by sending a KeyboardInterrupt to a Python process (presumably by sending the process a SIGINT signal). The complaint then seems to be that if the signal occurs while the Python process is in an asyncio task that is running some time-consuming code (either time.sleep() or some long-running computation) it interrupts the asyncio event loop and everything gets stopped.

Do I have that right?

If that is indeed the problem, the solution might be as simple as running the asyncio event loop in a separate thread, while the main thread just waits forever until a signal arrives. It can then catch the KeyboardInterrupt exception and in response send some callback to the thread running the asyncio event loop (e.g. using loop.call_soon_threadsafe()).

If I didn't understand the problem correctly, could you indicate whether you are still interested in keeping this issue open?

@IlianIliev
Copy link

Hi @gvanrossum, it was quite a surprise to see a response from the Python creator himself, and then you for spending time to look at this.

You have correctly understood the problem, and what you proposed is probably going to work, another workaround is wrapping each task in a try/except.

What I am trying to understand is why we have this inconsistent behavior between running in async and non-async mode, and whether this is the expected way for the interpreter to behave.

@gvanrossum
Copy link
Member

Yes, this is how it is supposed to work.

@IlianIliev
Copy link

IlianIliev commented Nov 28, 2023

I understand, thank you. I believe you can close the ticket in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-asyncio type-bug An unexpected behavior, bug, or error
Projects
Status: Done
Development

No branches or pull requests

3 participants