Asyncify request_transport context manager#7209
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7209 +/- ##
==========================================
+ Coverage 79.63% 79.64% +0.02%
==========================================
Files 565 565
Lines 43710 43762 +52
==========================================
+ Hits 34802 34851 +49
- Misses 8908 8911 +3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
971e821 to
5b3d4d4
Compare
| self._enters += 1 | ||
| else: | ||
| self.open() | ||
| self._enters += 1 |
There was a problem hiding this comment.
Isn't this logic simpler?
if self.is_open:
self.open()
self._enters += 1Right now you have a logic that considers self._enters aand self.is_open but also assumes that it works the same to work properly.
There was a problem hiding this comment.
Okay this is just taken over from somewhere else in transport. Then we do not touch this logic in this PR. Maybe in a subsequent PR but its not that important
There was a problem hiding this comment.
This caught my attention as well, would be good to clean up.
There was a problem hiding this comment.
Thanks @danielhollas
ok, the logic which was used in three places, is now moved into a set of helper functions.
| empty_ctx = contextvars.Context() | ||
| open_callback_handle = empty_ctx.run(self._loop.create_task, do_open()) | ||
| # Note: after making do_open async, we use create_task instead of call_later. | ||
| # Passing `context` to create_task is only supported in Python 3.11+, so we use | ||
| # empty_ctx.run() to ensure the task inherits an empty context. | ||
| # Once the minimum supported Python version is 3.11, this can be simplified to: | ||
| # open_callback_handle = self._loop.create_task(do_open(), context=contextvars.Context()) |
There was a problem hiding this comment.
@agoscinski regarding your question about call_later:
call_later is only for synchronous callbacks, not coroutines. Since do_open was made async, call_later can't be used with it.
If you think the comment here is verbose, I could reduce to something like
| empty_ctx = contextvars.Context() | |
| open_callback_handle = empty_ctx.run(self._loop.create_task, do_open()) | |
| # Note: after making do_open async, we use create_task instead of call_later. | |
| # Passing `context` to create_task is only supported in Python 3.11+, so we use | |
| # empty_ctx.run() to ensure the task inherits an empty context. | |
| # Once the minimum supported Python version is 3.11, this can be simplified to: | |
| # open_callback_handle = self._loop.create_task(do_open(), context=contextvars.Context()) | |
| empty_ctx = contextvars.Context() | |
| open_callback_handle = empty_ctx.run(self._loop.create_task, do_open()) | |
| # self._loop.create_task supports passing a context but only after Python 3.11+ |
There was a problem hiding this comment.
I reduced the comment
|
@khsrali would you mind expanding the PR description to explain what this PR is solving? It's very hard to tell just by reading the code, without knowing the details of the current Transport implementation. (Is there an issue open for this?) |
|
Hi @danielhollas This PR, is pre-requisite (and also general improvement!) for the upcoming #7206 (-> get rids of This PR removes two nested coroutine loops (calling on open() and close() that they internally call on The |
danielhollas
left a comment
There was a problem hiding this comment.
Thanks for the context @khsrali
I don't have capacity to do careful review but looks good on brief look.
| self._enters += 1 | ||
| else: | ||
| self.open() | ||
| self._enters += 1 |
There was a problem hiding this comment.
This caught my attention as well, would be good to clean up.
f3967ac to
88bf124
Compare
agoscinski
left a comment
There was a problem hiding this comment.
Just one comment. You decide if you want to change it back.
| Manages the ``_enters`` reference counter. If the transport is already open | ||
| (e.g. opened externally), an extra count is added so the final exit won't close it. | ||
| """ | ||
| need_open = False |
There was a problem hiding this comment.
I am not entirely sure about decoupling it. Its usage can be now
self._track_enter()
await something # another self._track_enter() happens that will also want to open it
self.open()Yes it is internal, but we developers make also mistakes, and you dont save many lines of code by reusing this function.
There was a problem hiding this comment.
yeah, vaild point.
I don't know what's the best practise here. Also repeating this code three times, is subject to mistake. 🤔
There was a problem hiding this comment.
Ok @agoscinski, I added a clear docstring that how _track_enter should be used.
I also added asyncio.lock for any potential race opening condition --which I believe there's no double opening in engine. But better to be safe than sorry.
This avoids two nested loops in transportQ