-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
Implement asyncio.Task.__cancel_requested__ #31313
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
Conversation
The design follows EdgeDB monkey-patch. Speaking about public API, I can imagine an alternative design:
I believe the proposed design is cleaner; it doesn't allow What do you think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks -- my concern here is that __cancel_requested__
is a rather unconventional API design. I would rather name it _cancel_requested
, which is in line with the other attributes, or if we want this to be a truly public API (not just something for private use by asyncio.TaskGroup
) make it a pair of methods, cancel_requested()
returning a bool
and set_cancel_requested()
taking a bool
.
@asvetlov I apologize, I didn't see your large comment with the alternative design before my own comment. This stuff is excruciating to understand (for me anyways, since I didn't write EdgeDb's TaskGroup :-) so I have to experiment some more. I will see if I can get the new TaskGroup to work with that, I will get back to you. |
@asvetlov I cannot get this to work. Here's what I did. (1) Implement
(2) In taskgroups.py: Disable task patching in taskgroups.py; delete the assignment (of False) to
(3) Disable the C accellerator at the top of
Now when I run
I get failures in Can you repro this? Can you explain or fix it? |
I think I understand the cause of the failure now (not sure this will lead to a fix yet). Test 15 has a try/except in the body of the async with TaskGroup() block, where in the try block it awaits a long sleep (which will be cancelled from the outside after 0.1 second), and the except catches CancelledError and then sleeps some more (0.5s) before re-raising it. During this second sleep a subtask crashes (0.3s into the test). The desired behavior here is that the sleep in the except block is not cancelled when the subtask crashes, and the sleep(0.5) is allowed to finish after which things reach (Test 16 is a variation where there's another task wrapping the whole business -- the outermost task is cancelled, and this is expected to be propagated into the nested task.) Because the initial cancellation of the parent task happens from the outside, it is essential that its I did find that none of the tests fail if I replace the line That's as far as I got. If we're going to design a public API for this, it would have to be a flag on tasks that is set when the task is cancelled, and which then stays set for the duration. We could add an API to reset the flag, which could be used by a task that catches cancellation and decides to ignore it (rather than just taking its time to clean up, like tests 15 and 16). Until the flag is cleared, further efforts to cancel the task are ignored. |
@asvetlov I would like to make progress on this. Mind if I just incorporate my version into the TaskGroup PR? My proposal is the following:
(@agronholm I think this may solve your problem too.) |
This means we no longer have to monkey-patch the parent task. It does introduce new semantics for task cancellation: When a task is cancelled, further attempts to cancel it have *no* effect unless the task calls self.uncancel(). Borrowed from pythonGH-31313 by @asvetlov.
Thanks, @gvanrossum |
Add
__cancel_requested__
property as discussed in #31270.cancel()
returnsFalse
is the task was previously cancelled already.No test is failing during the
cancel()
behavior change.