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
asyncio: Future.set_result() called on cancelled Future raises asyncio.futures.InvalidStateError #66085
Comments
Ok, I found a way to reproduce the error InvalidStateError in asyncio. I'm not sure that it's the same the error in bpo-21447. Output of attached bug.py in debug mode: Exception in callback Future.set_result(None)
handle: <TimerHandle when=79580.878306285 Future.set_result(None)>
source_traceback: Object created at (most recent call last):
File "/home/haypo/bug.py", line 11, in <module>
loop.run_until_complete(task2)
File "/home/haypo/prog/python/default/Lib/asyncio/base_events.py", line 239, in run_until_complete
self.run_forever()
File "/home/haypo/prog/python/default/Lib/asyncio/base_events.py", line 212, in run_forever
self._run_once()
File "/home/haypo/prog/python/default/Lib/asyncio/base_events.py", line 912, in _run_once
handle._run()
File "/home/haypo/prog/python/default/Lib/asyncio/events.py", line 96, in _run
self._callback(*self._args)
File "/home/haypo/prog/python/default/Lib/asyncio/tasks.py", line 241, in _step
result = next(coro)
File "/home/haypo/prog/python/default/Lib/asyncio/coroutines.py", line 72, in __next__
return next(self.gen)
File "/home/haypo/prog/python/default/Lib/asyncio/tasks.py", line 487, in sleep
h = future._loop.call_later(delay, future.set_result, result)
Traceback (most recent call last):
File "/home/haypo/prog/python/default/Lib/asyncio/events.py", line 96, in _run
self._callback(*self._args)
File "/home/haypo/prog/python/default/Lib/asyncio/futures.py", line 326, in set_result
raise InvalidStateError('{}: {!r}'.format(self._state, self))
asyncio.futures.InvalidStateError: CANCELLED: <Future cancelled> The fix is to replace the following line of sleep(): h = future._loop.call_later(delay, future.set_result, result) with: def maybe_set_result(future, result):
if not future.cancelled():
future.set_result(result)
h = future._loop.call_later(delay, maybe_set_result, future, result) This generic issue was already discussed there: A patch was also proposed: |
I see two options to fix this issue:
Patch "Add ignore_cancelled and ignore_done to Future.set_result()" (for Tulip): Patch "Add Future._maybe_set_result()": I prefer the second patch because it doesn't touch the public API and it is shorter. Note: the first patch contains unrelated changes, like checking fut.cancelled() instead of fut.done(). "_maybe_set_result()" is not a good name. Other suggestions: "_set_result_except_cancelled", ""_set_result_ignore_cancelled". |
In https://codereview.appspot.com/69870048/ Guido proposed to test to replace: |
I read again the mail thread and Guido proposed the nice name _set_result_unless_cancelled() which is very explicit. I updated my patch: |
New changeset d7e4efd5e279 by Victor Stinner in branch '3.4': New changeset 50c995bdc00a by Victor Stinner in branch 'default': |
Fix commited to Tulip (4655ef2d9f43), Python 3.4 and 3.5. |
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:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: