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

asyncio: Future.set_result() called on cancelled Future raises asyncio.futures.InvalidStateError #66085

Closed
vstinner opened this issue Jun 30, 2014 · 6 comments

Comments

@vstinner
Copy link
Member

BPO 21886
Nosy @vstinner
Files
  • bug.py
  • 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 = <Date 2014-07-05.13:31:25.362>
    created_at = <Date 2014-06-30.14:05:18.966>
    labels = []
    title = 'asyncio: Future.set_result() called on cancelled Future raises asyncio.futures.InvalidStateError'
    updated_at = <Date 2014-07-05.13:32:06.138>
    user = 'https://github.com/vstinner'

    bugs.python.org fields:

    activity = <Date 2014-07-05.13:32:06.138>
    actor = 'vstinner'
    assignee = 'none'
    closed = True
    closed_date = <Date 2014-07-05.13:31:25.362>
    closer = 'python-dev'
    components = []
    creation = <Date 2014-06-30.14:05:18.966>
    creator = 'vstinner'
    dependencies = []
    files = ['35807']
    hgrepos = []
    issue_num = 21886
    keywords = []
    message_count = 6.0
    messages = ['221961', '221994', '221995', '221996', '222357', '222359']
    nosy_count = 3.0
    nosy_names = ['vstinner', 'python-dev', 'ryder.lewis']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue21886'
    versions = ['Python 3.5']

    @vstinner
    Copy link
    Member Author

    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:
    https://groups.google.com/forum/?fromgroups#!searchin/python-tulip/set_result$20InvalidStateError/python-tulip/T1sxLqjuoVY/YghF-YsgosgJ

    A patch was also proposed:
    https://codereview.appspot.com/69870048/

    @vstinner
    Copy link
    Member Author

    I see two options to fix this issue:

    • add an optional parameter to set_result() to do nothing if the future is cancelled
    • add a method (public or private) to set a result or do nothing if the future is cancelled

    Patch "Add ignore_cancelled and ignore_done to Future.set_result()" (for Tulip):
    http://codereview.appspot.com/109340043

    Patch "Add Future._maybe_set_result()":
    http://codereview.appspot.com/108300043

    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".

    @vstinner
    Copy link
    Member Author

    In https://codereview.appspot.com/69870048/ Guido proposed to test to replace:
    self._loop.call_soon(waiter.set_result, None)
    with:
    if not waiter.cancelled():
    waiter.set_result(None)

    @vstinner
    Copy link
    Member Author

    "_maybe_set_result()" is not a good name. Other suggestions: "_set_result_except_cancelled", ""_set_result_ignore_cancelled".

    I read again the mail thread and Guido proposed the nice name _set_result_unless_cancelled() which is very explicit. I updated my patch:
    http://codereview.appspot.com/108300043

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jul 5, 2014

    New changeset d7e4efd5e279 by Victor Stinner in branch '3.4':
    Closes bpo-21886, bpo-21447: Fix a race condition in asyncio when setting the result
    http://hg.python.org/cpython/rev/d7e4efd5e279

    New changeset 50c995bdc00a by Victor Stinner in branch 'default':
    (Merge 3.4) Closes bpo-21886, bpo-21447: Fix a race condition in asyncio when setting
    http://hg.python.org/cpython/rev/50c995bdc00a

    @python-dev python-dev mannequin closed this as completed Jul 5, 2014
    @vstinner
    Copy link
    Member Author

    vstinner commented Jul 5, 2014

    Fix commited to Tulip (4655ef2d9f43), Python 3.4 and 3.5.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    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

    No branches or pull requests

    1 participant