-
-
Notifications
You must be signed in to change notification settings - Fork 750
Avoid deadlock when two tasks are concurrently waiting for an unresolved ActorFuture
#5709
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
|
Can one of the admins verify this patch? |
43bb3d2 to
95f11e9
Compare
f2a84c5 to
cb8e7de
Compare
ian-r-rose
left a comment
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 @graingert, this is a nice piece of work, and the implementation seems sound to me. A few design questions, but nothing major.
1a09c7e to
f2fbc8a
Compare
gjoseph92
left a comment
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.
Not too important, but I could see some type annotations here being helpful, mostly just for future readers. Particularly for things like:
-
ActorFuture.resultreturn type (makingActorFuturegeneric would be necessary) -
ActorFuture.__await__return type -
_ActorFuture._out
6549929 to
6e54fd1
Compare
6e54fd1 to
35b0c65
Compare
|
Hmm, tried your PR with Python 3.10.1 and the results were not completely conclusive: Complete build log with all packages used and step taken to run the test suite. |
| await self._event.wait() | ||
| out = self._out | ||
| assert out is not None | ||
| return out.unwrap() |
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.
Can you elucidate a bit more the purpose of these wrapper classes, as opposed to the more direct inspection of the result that there was previously? It seems like they are related to trying to get a chain of custody for the generic _T, but I'm not sure it really buys much since the setting of the result here isn't checked, so we ultimately have an _OK(Unknown).
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.
Yeah ideally this would have been done with TypedDict but they're not supported python/mypy#3863
class _OK(TypedDict, Generic[_T]):
status: Literal["OK"]
result: _T
class _Error(TypedDict):
status: Literal["error"]
exception: Exception
...
def _set_result(self, out: _Error | _OK[_T]): ...It seems like they are related to trying to get a chain of custody for the generic _T, but I'm not sure it really buys much since the setting of the result here isn't checked, so we ultimately have an _OK(Unknown).
I needed to draw the line somewhere of what's typed and what's not in this PR, and chose to type all the methods and classes of BaseActorFuture. _Error | _OK[_T] | None is also needed for the internal state ActorFuture so I think it's worth it for now
|
I love the new generic machinery @graingert, and I like that it brings it a bit closer to how |
749bce9 to
0364c50
Compare
7fde98b to
a4012e5
Compare
this keeps the somewhat odd late asyncio.Event() construction in one location that can be removed by pyupgrade
each test uses a different method so it's confusing me to edit both ends of the test file
…rActorFuture->EagerActorFuture
a4012e5 to
2a7b3e4
Compare
|
Waiting for builds to pass and then will merge. |
ActorFuture
|
All green 🥲 |
ian-r-rose
left a comment
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.
Looks great
|
Was this supposed to be python310-fix? Because it doesn’t work for me: test_client.py::test_client_gather_semaphore_loop, |
|
Thank you @graingert ! This looks great. Sorry for us taking so long with reviewing it. |
pre-commit run --all-files