Skip to content

Defer #3819

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

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft

Defer #3819

wants to merge 29 commits into from

Conversation

patrick91
Copy link
Member

@patrick91 patrick91 commented Mar 25, 2025

Another attempt :D

Summary by Sourcery

Implement experimental incremental execution in the GraphQL schema to support deferred and streamed responses. Refactor the async run method to handle incremental execution results. Add end-to-end tests for Apollo and Relay clients, and introduce a new CI workflow for running these tests.

New Features:

  • Introduce experimental incremental execution support in the GraphQL schema, allowing for deferred and streamed responses.

Enhancements:

  • Refactor the async run method to handle GraphQLIncrementalExecutionResults, enabling streaming responses for incremental execution.

CI:

  • Add a new GitHub Actions workflow for running end-to-end tests using Playwright.

Documentation:

  • Add a README file for the e2e directory, providing setup and configuration instructions for React, TypeScript, and Vite.

Tests:

  • Add end-to-end tests for GraphQL queries using Apollo and Relay clients, including tests for deferred and streamed responses.

Copy link
Contributor

sourcery-ai bot commented Mar 25, 2025

Reviewer's Guide by Sourcery

This pull request introduces experimental incremental execution support in the GraphQL server, adds new e2e tests for Apollo and Relay clients, and updates the GraphiQL interface. It also includes various refactorings and enhancements across the codebase.

Sequence diagram for incremental execution in GraphQL server

sequenceDiagram
    participant Client
    participant Server
    participant GraphQL
    Client->>Server: Send GraphQL request
    Server->>GraphQL: Execute request
    alt Incremental Execution Enabled
        GraphQL->>Server: Return initial result
        Server->>Client: Send initial result
        loop While more results
            GraphQL->>Server: Return subsequent result
            Server->>Client: Send subsequent result
        end
    else Standard Execution
        GraphQL->>Server: Return final result
        Server->>Client: Send final result
    end
Loading

Class diagram for updated GraphQL execution

classDiagram
    class GraphQLSchema {
        +query: QueryType
        +mutation: MutationType
        +subscription: SubscriptionType
        +directives: List<Directive>
    }
    class GraphQLIncrementalExecutionResults {
        +initial_result: ExecutionResult
        +subsequent_results: List<ExecutionResult>
    }
    class StrawberryConfig {
        +enable_experimental_incremental_execution: bool
    }
    GraphQLSchema --> GraphQLIncrementalExecutionResults
    GraphQLSchema --> StrawberryConfig
Loading

File-Level Changes

Change Details Files
Implemented experimental incremental execution support in the GraphQL server.
  • Added support for GraphQLIncrementalExecutionResults in the async_base_view.py.
  • Modified the schema to include experimental directives for incremental execution.
  • Updated the execute and execute_sync functions to use experimental_execute_incrementally when enabled.
  • Introduced a new configuration option to enable experimental incremental execution.
strawberry/http/async_base_view.py
strawberry/schema/schema.py
strawberry/schema/config.py
strawberry/schema/_graphql_core.py
Added end-to-end tests for Apollo and Relay clients.
  • Created new components for Apollo and Relay tests.
  • Set up a new Express server for testing with GraphQL schema.
  • Configured Playwright for running e2e tests.
  • Added test cases for basic queries and deferred execution.
e2e/src/components/apollo-tests.tsx
e2e/src/components/relay-tests.tsx
e2e/app.ts
e2e/playwright.config.ts
e2e/src/tests/graphql-clients.spec.ts
Updated GraphiQL interface to the latest version.
  • Changed the GraphiQL CSS and JS to version 3.8.3.
  • Updated the HTML structure for the GraphiQL page.
strawberry/static/graphiql.html
Refactored and improved the test setup for HTTP clients.
  • Moved test files to a new directory structure.
  • Updated import paths for HTTP client tests.
  • Added new test cases for deferred and stream operations.
tests/http/test_multipart_subscription.py
tests/http/incremental/test_defer.py
tests/http/incremental/conftest.py
Miscellaneous improvements and refactoring.
  • Added a new Hero type in the schema for testing.
  • Improved error handling in the process_result function.
  • Updated the ESLint configuration for the e2e project.
tests/views/schema.py
strawberry/http/__init__.py
e2e/eslint.config.js

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@botberry
Copy link
Member

botberry commented Mar 25, 2025

Apollo Federation Subgraph Compatibility Results

Federation 1 Support Federation 2 Support
_service🟢
@key (single)🟢
@key (multi)🟢
@key (composite)🟢
repeatable @key🟢
@requires🟢
@provides🟢
federated tracing🔲
@link🟢
@shareable🟢
@tag🟢
@override🟢
@inaccessible🟢
@composeDirective🟢
@interfaceObject🟢

Learn more:

Copy link

codecov bot commented Mar 25, 2025

Codecov Report

Attention: Patch coverage is 45.06173% with 89 lines in your changes missing coverage. Please review.

Project coverage is 94.79%. Comparing base (be6caa0) to head (876d580).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3819      +/-   ##
==========================================
- Coverage   95.04%   94.79%   -0.25%     
==========================================
  Files         502      506       +4     
  Lines       32682    32824     +142     
  Branches     1695     1715      +20     
==========================================
+ Hits        31061    31115      +54     
- Misses       1348     1430      +82     
- Partials      273      279       +6     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +20 to +21
if isinstance(result, GraphQLIncrementalExecutionResults):
return result
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to support this properly

Comment on lines 386 to 389
# for Apollo
# content type is `multipart/mixed;deferSpec=20220824,application/json`
"path": ["blogPost"],
"label": "relayTestsBlogPostQuery$defer$relayTestsCommentsFragment",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should not be hard-coded, in any case having both label and path seems to be ok for both relay and apollo, so we might want to keep them

tbd if we want to keep the .formatted instead of using our own wrappers

apparently there's no good way to define what spec a client is supporting (Apollo sends deferSpec=20220824, but for relay it's up to whoever implements the fetch)

Comment on lines +272 to +273
if self.config.enable_experimental_incremental_execution:
directives = tuple(directives) + tuple(incremental_execution_directives)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to throw errors if user what experimental execution but we are not on graphql core 3.3+

Comment on lines +550 to +551
# TODO: maybe here use the first result from incremental execution if it exists
if isinstance(result, GraphQLExecutionResult) and result.errors:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what I meant with that comment :D

but we should probably get rid of the isinstance check?

@@ -0,0 +1,44 @@
import contextlib
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this from the previous location

"data": {"character": {"id": "1"}},
"hasNext": True,
"pending": [{"path": ["character"], "id": "0"}],
# TODO: check if we need this and how to handle it
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could support these in a future version

@@ -4,8 +4,7 @@
import pytest
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file was also moved

Copy link

codspeed-hq bot commented Mar 25, 2025

CodSpeed Performance Report

Merging #3819 will not alter performance

Comparing feature/defer (876d580) with main (be6caa0)

Summary

✅ 21 untouched benchmarks

@botberry
Copy link
Member

botberry commented Mar 31, 2025

Pre-release

👋

Pre-release 0.266.0.dev.1744797470 [876d580] has been released on PyPi! 🚀
You can try it by doing:

poetry add strawberry-graphql==0.266.0.dev.1744797470

@strawberry-graphql strawberry-graphql deleted a comment from botberry Mar 31, 2025
@patrick91
Copy link
Member Author

/pre-release

codeflash-ai bot added a commit that referenced this pull request Mar 31, 2025
…efer`)

To optimize the provided code, we can reduce the number of checks by combining related conditionals and accessing properties once instead of multiple times. Furthermore, we can streamline the creation of the `data` dictionary. Here is an optimized version of the code.



In this optimized version.
- We access `result.errors` and `result.extensions` once and store their values in the `errors` and `extensions` variables, respectively.
- We use dictionary unpacking with conditionals to add the "errors" and "extensions" keys to `data` only when they are present.

This should provide a minor performance improvement while maintaining the same functionality.
Copy link

codeflash-ai bot commented Mar 31, 2025

⚡️ Codeflash found optimizations for this PR

📄 100% (1.00x) speedup for process_result in strawberry/http/__init__.py

⏱️ Runtime : 1.78 millisecond 892 microseconds (best of 28 runs)

I created a new dependent PR with the suggested changes. Please review:

If you approve, it will be merged into this PR (branch feature/defer).

@patrick91
Copy link
Member Author

/pre-release

@matclayton
Copy link

Screenshot 2025-04-02 at 17 30 34

Did a quick test on this and fairly sure I've got the following crash. Its possible I've misconfigured something, but this is best understanding on how to enable it

…efer`) (#3827)

Co-authored-by: codeflash-ai[bot] <148906541+codeflash-ai[bot]@users.noreply.github.com>
Copy link

codeflash-ai bot commented Apr 15, 2025

This PR is now faster! 🚀 @patrick91 accepted my optimizations from:

Copy link

codeflash-ai bot commented Apr 15, 2025

This PR is now faster! 🚀 codeflash-ai[bot] accepted my code suggestion above.

@patrick91
Copy link
Member Author

@matclayton sorry, I totally missed that message! do you know if you can write a small reproduction? or was that fixed with GraphQL-core 3.3.0a7?

@matclayton
Copy link

Sorry I didn't follow up here, this is fixed in GraphQL core 3.3.0va7, btw we're running GraphQL-core 3.3.0v7 in prod now, and not seen a single issue so far. Need to still confirm the other bits of this PR, I'm hoping the team can take it off me the next week or so.

@patrick91
Copy link
Member Author

/pre-release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants