-
-
Notifications
You must be signed in to change notification settings - Fork 129
Add lock to ReAwaitable for concurrent awaits #2109
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
base: master
Are you sure you want to change the base?
Conversation
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
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!
|
||
|
||
async def sample_coro(): | ||
await anyio.sleep(0.1) |
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.
await anyio.sleep(0.1) | |
await anyio.sleep(1) |
give less chance for random failures.
|
||
@pytest.mark.anyio | ||
async def test_concurrent_awaitable(): | ||
reawaitable = ReAwaitable(sample_coro()) |
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.
Please, add a link to the original bug on github.
from returns.primitives.reawaitable import ReAwaitable | ||
|
||
|
||
async def sample_coro(): |
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.
async def sample_coro(): | |
async def sample_coro() -> str: |
|
||
|
||
@pytest.mark.anyio | ||
async def test_concurrent_awaitable(): |
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.
async def test_concurrent_awaitable(): | |
async def test_concurrent_awaitable() -> None: |
returns/primitives/reawaitable.py
Outdated
@@ -2,6 +2,8 @@ | |||
from functools import wraps | |||
from typing import NewType, ParamSpec, TypeVar, cast, final | |||
|
|||
import anyio |
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.
It is not in list of production deps:
Lines 51 to 57 in bbfc3d3
[tool.poetry.dependencies] | |
python = "^3.10" | |
typing-extensions = ">=4.0,<5.0" | |
pytest = { version = "^8.0", optional = true } | |
hypothesis = { version = "^6.122", optional = true } | |
mypy = { version = ">=1.12,<1.16", optional = true } |
Can we use if
s to find the correct lock type?
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 see, but unfortunately i am not familiar with other libraries than pure asyncio
.
Is it appropriate to use asyncio.Lock
?
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.
Thank you for the fast review!
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.
ah maybe something like this?
try:
import anyio
Lock = anyio.Lock
except ImportError:
import asyncio
Lock = asyncio.Lock
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.
yes, this try
is fine :)
0c8f6b6
to
4d646e9
Compare
ec52eca
to
94d5b1f
Compare
…ot available and improve test types
33f89f9
to
3e7fed1
Compare
c4300c0
to
2d8ae80
Compare
1569389
to
a1206af
Compare
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! Last comments
tests/test_primitives/test_reawaitable/test_reawaitable_concurrency.py
Outdated
Show resolved
Hide resolved
tests/test_primitives/test_reawaitable/test_reawaitable_concurrency.py
Outdated
Show resolved
Hide resolved
tests/test_primitives/test_reawaitable/test_reawaitable_concurrency.py
Outdated
Show resolved
Hide resolved
…rency.py Co-authored-by: sobolevn <[email protected]>
…rency.py Co-authored-by: sobolevn <[email protected]>
Co-authored-by: sobolevn <[email protected]>
…rency.py Co-authored-by: sobolevn <[email protected]>
Thank you! I hope this works. |
returns/primitives/reawaitable.py
Outdated
|
||
Lock = asyncio.Lock | ||
else: | ||
Lock = anyio.Lock |
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.
You can type it as a simple interface that only supports async with
, probably like contextlib.AbstractAsyncContextManager
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.
Please, don't forget to document that we may require anyio
lib in this function for trio
- Add notes that anyio is required for proper trio support - Add type annotation for Lock variable - Document the asyncio.Lock fallback behavior 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
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 like we would have to use a custom protocol :(
I have made things!
Fix for issue: #2108
Checklist
Related issues
This PR addresses the issue where multiple concurrent awaits on the same ReAwaitable instance could lead to unexpected behavior. By adding a lock around the critical section in the _awaitable method, we ensure that the coroutine is only awaited once even when multiple tasks await the same ReAwaitable concurrently.
The PR includes a test case that demonstrates concurrent awaiting works correctly with the lock in place.
🙏 Please, if you or your company finds \ valuable, help us sustain the project by sponsoring it transparently on https://github.com/sponsors/dry-python.