-
-
Notifications
You must be signed in to change notification settings - Fork 530
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
Use our own iterator to iterate and transform subscription results #2724
Use our own iterator to iterate and transform subscription results #2724
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #2724 +/- ##
==========================================
- Coverage 96.45% 96.44% -0.02%
==========================================
Files 198 198
Lines 8244 8190 -54
Branches 1500 1482 -18
==========================================
- Hits 7952 7899 -53
+ Misses 184 183 -1
Partials 108 108 |
Thanks for adding the Here's a preview of the changelog: We use a simpler and more performant iterator to iterate over subscription results. Here's the tweet text:
|
Can't find where the coverage tests are failing... Are these tests actually correct? |
@kristjanvalur I don't this so, not sure if it is a misconfiguration or just coverage being bad |
I'd like to vote for this but also offer a suggestion / request - can the translation be moved further up the chain into the In particular, with the unit tests, the fact that To clarify what I'm suggesting I've made a commit on top of this branch, though its just a suggestion (I've tested this works in my context but I'm not sure if it impacts the strawberry test suite/mypy): mixcloud@2fb568a |
Yes, I see. This is not a bad idea, and it will help to simplify some other things as well. It probably ties in with some other discussions, such as this here: #2701 (subscriptions returns an iterator over graphql-core results, whereas other schema operations return straqberry's own result types.) I guess that a very valid first step is that graphql's schema returns its own AsyncGenerator (or a result in case of error)), until we decide what kind of tranformation of the results themselves is necessary (I think it has mostly to do with extensions which aren't supported at the moment for subscriptions). Allow me to modify this PR accordingly. |
d01f3cb
to
b11af2f
Compare
b11af2f
to
21384ee
Compare
@jthorniley something like this? The current iterator truly is a can of worms. Cancelling it can result in unpredictable behaviour. For example, during processing of a the error currently visible in the the unit tests is actually due to this. We are trying to measure the responsiveness of code which isn't well predictable. I already tried making this unit test work without timing, but was foiled by the above, CancelledErrors coming out of nowhere. |
21384ee
to
d768f87
Compare
Yep, in terms of the processing being done inside subscribe, this is in line with what I was thinking - thanks! |
After fixing the subscription iterator, it is finally possible to get deterministic behaviour for subscription finalizers. Previously they could get bot GeneratorExit and a CancelledError. it made it impossible to do any async logic in there, like wait for condition variables etc. I have fixed the test verifying that subscription cancellation does not block the connection, by using synchronization primitives rather than timeout measruements. |
This can also now be expanded upon to add extension processing to subscriptions. |
10bf79d
to
7616426
Compare
…erator based version" This reverts commit b840f97.
…an Async Generator
…ictably with the new AsyncGenerator
7616426
to
8658699
Compare
graphql-core has this functionality in https://github.com/graphql-python/graphql-core/releases/tag/v3.3.0a3 |
Closing this one because the upstream patch landed and extension support for subscriptions has been added in another PR. Thanks so much for this PR and keeping it updated a few times. |
Provide a generator based iterator to iterate over and transform the subscription results from graphql core.
Description
In graphql-python/graphql-core#197 I descibe how the iterator provided by graphql core is
problematic. Its
aclose()
semantics are unexpected and iteration happens on a subtask. A much simpler approach is possible which is both more performant (no subtasks), more easily debuggable (call stack isn't broken on__anext__()
and whereawait acancel()
actually only returns when the iterator has been fully cancelled.A concrete problem with the current iterator is that during the handling of a
GeneratorExit
exception, e.g. in afinally:
clause entered because the generator is closed, it is likely that one receives aCancelledError
if one tries to do anyasync
operations. This makes it hard to write test which test the finalization of subscriptions, and will make it impossible to do proper cleanup of async resources in case of subscription cancellation. This does not happen using regular async-generators.We inspect the iterator we get from graphql-core. If it appears to be the old type with its internal
_close_event
, we replace it with our own implementation.This is intended as an interim solution until graphql-core provides a better iterator which more closely conforms to the semantics one is to expect from Python's AsyncGenerators.
The change helps avoid the strange "RuntimeErrors()" we were seeing when calling
aclose()
despite doing so in a legalway from the same task which was iterating, and in a sense is a bugfix.
It should also be noted that an iterator implemented this way, with an Async Generator, does not require an explicit call to "aclose()" since it will be scheduled when it goes out of scope. But expliticly doing so may be prudent if one wants the cleanup to happen promptly.
Upstream I have submitted both In graphql-python/graphql-core#197 and graphql-python/graphql-core#199. It is unclear if and when these will ever be accepted. Regardless of that, this PR also provides a framework for adding support for extensions to subscriptions, since they would need a custom iterator anyway.
Types of Changes
Issues Fixed or Closed by This PR
Checklist