-
Notifications
You must be signed in to change notification settings - Fork 1.1k
PYTHON-5219 - Avoid awaiting coroutines when holding locks #2250
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
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -240,16 +240,20 @@ async def open(self) -> None: | |
"https://dochub.mongodb.org/core/pymongo-fork-deadlock", | ||
**kwargs, | ||
) | ||
close_servers = [] | ||
async with self._lock: | ||
# Close servers and clear the pools. | ||
for server in self._servers.values(): | ||
await server.close() | ||
close_servers.append(server) | ||
if not _IS_SYNC: | ||
self._monitor_tasks.append(server._monitor) | ||
|
||
# Reset the session pool to avoid duplicate sessions in | ||
# the child process. | ||
self._session_pool.reset() | ||
|
||
for server in close_servers: | ||
await server.close() | ||
|
||
async with self._lock: | ||
await self._ensure_opened() | ||
|
||
|
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.
We close the servers here but we leave
self._servers
untouched? Is using a client post fork broken right now? I don't see where the Server gets recreated.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.
Our
test_fork.py
tests are all passing. We re-open each server inself._servers
in_ensure_opened
, called at the end ofopen
here.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.
Here's the race I'm concerned about:
It could be that this is already possible with the current code. 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.
The addition of async hasn't changed the structure of this code, only the async/await syntax, so if this race condition does exist, it's existed for some time. Here's the identical PyMongo 4.8 version, before we added async support:
mongo-python-driver/pymongo/topology.py
Line 177 in de0f46a
I agree looking at the code that scenario certainly seems possible. We could add a flag set post-fork to prevent that race condition?
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 concerned about async here. I'm concerned that delaying the server.close() call to after we release the lock will make this race more likely.
Uh oh!
There was an error while loading. Please reload this page.
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.
I just realized: since we don't support fork + async at all, this change is also non-functional and can be reverted.
I mention that this code hasn't changed beside the addition of async to show that this race condition has either been present for quite some time, or doesn't exist.
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 let's undo the forking changes. Holding the lock while calling close() in the sync version isn't so bad in this case because it only happens once post fork().