fix!: ensure that generator clean up is correctly propagated#4394
fix!: ensure that generator clean up is correctly propagated#4394winstxnhdw wants to merge 10 commits intolitestar-org:mainfrom
Conversation
428fb6e to
3beb444
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4394 +/- ##
==========================================
- Coverage 97.83% 97.78% -0.05%
==========================================
Files 296 296
Lines 15286 15315 +29
Branches 1711 1716 +5
==========================================
+ Hits 14955 14976 +21
- Misses 189 197 +8
Partials 142 142 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
I believe this is closer to what you want? We make In the end, this should probably be considered a fix since this fixes a discrepancy in clean up between async and sync generators. |
446cb97 to
8a47ccd
Compare
8cbaf83 to
8db6397
Compare
03b4344 to
326e55a
Compare
| try: | ||
| yield data.file_content | ||
| while True: | ||
| yield data.file_content | ||
| await sleep(0.1) |
There was a problem hiding this comment.
Finally found the issue with the test. The SSE needs to continuously yield something otherwise the generator cannot handle the athrow. Is this something we should be worried about?
|
Marking this as breaking again because async generators will no longer clean up by default as we no longer call |
| elif isinstance(iterator, AsyncIteratorWrapper): | ||
| self._original_generator = iterator._original_generator | ||
| else: | ||
| self._original_generator = iterable_to_generator(iterator) |
There was a problem hiding this comment.
This line is still necessary for asend because asend needs a return value.
9ed342a to
38221a4
Compare
|
Documentation preview will be available shortly at https://litestar-org.github.io/litestar-docs-preview/4394 |
| elif isinstance(iterator, AsyncIteratorWrapper): | ||
| self._original_generator = iterator._original_generator |
There was a problem hiding this comment.
This fundamentally changes the functionality of AsyncIteratorWrapper. It's supposed to wrap a synchronous iterable / iterator, and turn it into an async iterable. Now with the added functionality of also wrapping instances of itself (?), it gets really confusing.
| if isinstance(self.iterator.content_async_iterator, AsyncGenerator): # type: ignore[attr-defined] | ||
| await self.iterator.content_async_iterator.athrow(ClientDisconnectError) # type: ignore[attr-defined] |
There was a problem hiding this comment.
Again, I do not understand why you have to be so over specific here. It should be good enough to simply check:
- Is it an async-generator?
athrow - Is it an async-iterable? Just
break
There was a problem hiding this comment.
The issue here is how _ServerSentEventIterator is designed. The content is kept in self.content_async_iterator, which means to close the original generator from the handler, we need to specifically throw self.iterator.content_async_iterator because self.iterator will only contain the header chunks like event_id, event_type, etc.
There was a problem hiding this comment.
_ServerSentEventIterator should handle that though, not the code that's calling it. It knows about its internal state, and is best suited to decide where to throw what exception. From the outside, it should be treated as any other async iterator / generator.
|
Hey @winstxnhdw, thanks for bringing up this issue and attempting to fix it! I know you've invested some time into this, so I'm sorry to say it, but I'll be closing this PR now though, since it doesn't seem to be getting into a state where I'd consider it mergeable, despite me sinking a lot of time into reviews, suggestions and conversations - time that could also have been spent fixing other (or this) bugs. Should you want to contribute again in the future, I suggest you try to familiarise yourself with the material a bit more, and approach changes with a more holistic view, i.e. think deeper about the side effects your changes might have, and the intention behind them. To that end, I can also recommend simply reaching out on our discord server, where we'll be happy to answer all questions :) |
|
you can also just put your PR as a draft and ask for anothers their pov if needed, I do that often when I try things and dont want to "pollute" other's workflow, which happens often for me, some PRs lead nowhere, as a draft it doesnt impact anyone else other than me. |
Description
As discussed on Discord, we should ensure that synchronous generators are properly cleaned up. Async generators will be cleaned up, so we should do the same for synchronous generators as well.
The following snippet will now properly print
"cleaned up inner"on premature disconnects.Closes #3772