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

🐛 FIX: Task.cancel should not set state as EXCEPTED #214

Merged
merged 6 commits into from
Mar 8, 2021

Conversation

chrisjsewell
Copy link
Member

See aiidateam/aiida-core#4648 (comment)
Currently, stopping the daemon in python 3.7 excepts all processes!

@chrisjsewell chrisjsewell requested review from muhrin and sphuber March 4, 2021 23:02
@codecov
Copy link

codecov bot commented Mar 4, 2021

Codecov Report

Merging #214 (afbe291) into develop (db0bf60) will decrease coverage by 0.06%.
The diff coverage is 60.00%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #214      +/-   ##
===========================================
- Coverage    90.57%   90.51%   -0.05%     
===========================================
  Files           22       22              
  Lines         2956     2961       +5     
===========================================
+ Hits          2677     2680       +3     
- Misses         279      281       +2     
Impacted Files Coverage Δ
plumpy/processes.py 91.90% <50.00%> (-0.13%) ⬇️
plumpy/process_states.py 88.71% <66.67%> (-0.26%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update db0bf60...afbe291. Read the comment docs.

@chrisjsewell
Copy link
Member Author

chrisjsewell commented Mar 4, 2021

The initial commit is the minimum required to fix the aiida-core bug, but actually cc99c5f should be a more "complete" fix

@@ -1193,6 +1193,12 @@ async def step(self) -> None:

except KeyboardInterrupt: # pylint: disable=try-except-raise
raise
except asyncio.CancelledError: # pylint: disable=try-except-raise
Copy link
Member

@ltalirz ltalirz Mar 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering: is cancellation conceptually also an interruption or should these two be treated differently?

In the other two cases above you're capturing the CancelledError together with the Interruption.
That makes me wonder whether Interruption should inherit from asyncio.CancelledError and we just generalize _set_interrupt_action_from_exception to deal properly also with that case?

Perhaps a question for @muhrin

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it's a bit subtle and it's difficult to give a good answer without looking through in detail all of the code you've been discussing.

However, my intuition is that CancelledError should not be treated as an interruption. My thinking is that, for futures (both concurrent and async), there are three terminal states (success, exception and cancelled) and ideally I would be tempted to keep them as such. Interrupted was created precisely to give another form of intervention for our specific use and, if possible, all interruptions would be channelled through this mechanism.

Copy link
Member

@ltalirz ltalirz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @chrisjsewell

Given that we're going to address elsewhere the issue of asyncio.CancelledErrors arriving at this part of the code, the purpose of this PR reduces to making sure the behavior under python3.7 and python3.8 is the same (which is still worthwhile).

@@ -316,7 +317,7 @@ def interrupt(self, reason: Any) -> None:
async def execute(self) -> State: # type: ignore # pylint: disable=invalid-overridden-method
try:
result = await self._waiting_future
except Interruption:
except (Interruption, asyncio.CancelledError):
Copy link
Member

@ltalirz ltalirz Mar 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to just make behavior under python3.7 the same as it currently is in and python3.8, let's only re-raise for the asyncio.CancelledError (i.e. treat it separately from the Interruption that also manipulates the self._waiting_future)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -229,7 +230,7 @@ async def execute(self) -> State: # type: ignore # pylint: disable=invalid-over
result = self.run_fn(*self.args, **self.kwargs)
finally:
self._running = False
except Interruption:
except (Interruption, asyncio.CancelledError):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it makes sense to also here make a separate case for asyncio.CancelledError and add the multi-line comment + add a note that this can be removed once support for python 3.7 is dropped

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 👍

plumpy/process_states.py Outdated Show resolved Hide resolved
@chrisjsewell chrisjsewell requested a review from ltalirz March 8, 2021 11:44
Copy link
Member

@ltalirz ltalirz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @chrisjsewell

to me this is good to merge

@chrisjsewell chrisjsewell merged commit 99f959b into develop Mar 8, 2021
@chrisjsewell chrisjsewell deleted the fix-step-cancel branch March 8, 2021 12:22
unkcpz pushed a commit to unkcpz/plumpy that referenced this pull request Dec 14, 2024
`asyncio.CancelledError` are generated when an async task is cancelled.
In python 3.7 it inherits from `Exception`,
whereas in python 3.8+ it inherits from `BaseException`.
This meant it python 3.7 it was being caught by the broad `except Exception`,
and setting the process state to EXCEPTED,
whereas in python 3.8+ it was being re-raised to the caller.
We now ensure in both versions it is re-raised.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants