strawberry icon indicating copy to clipboard operation
strawberry copied to clipboard

Do not block `graphql_transport_ws` operations while creating context or validating a single request operation

Open kristjanvalur opened this issue 2 years ago β€’ 13 comments

Now both Context creation and validation of an operation (subscripton or single-result operation) are performed on the worker task, freeing up the Websocket for other requests.

Description

Previously both creating the context, and validating the request, were done on the same task which handles incoming messages for the Websocket. Both of these operations are async and can potentially take a long time. Now they are performed on the worker background Task which is created to handle the operation.

We add tests to make sure that long operations in context and validation don't block the websocket connection.

Types of Changes

  • [x] Core
  • [ ] Bugfix
  • [ ] New feature
  • [x] Enhancement/optimization
  • [ ] Documentation

Issues Fixed or Closed by This PR

Checklist

  • [x] My code follows the code style of this project.
  • [x] My change requires a change to the documentation.
  • [x] I have updated the documentation accordingly.
  • [x] I have read the CONTRIBUTING document.
  • [x] I have added tests to cover my changes.
  • [x] I have tested the changes and verified that they work and don't break anything (as well as I can manage).

kristjanvalur avatar Jun 08 '23 14:06 kristjanvalur

Codecov Report

Attention: Patch coverage is 99.33333% with 1 line in your changes missing coverage. Please review.

Project coverage is 96.53%. Comparing base (fc25e04) to head (e43aca8). Report is 53 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2829      +/-   ##
==========================================
- Coverage   96.79%   96.53%   -0.27%     
==========================================
  Files         517      517              
  Lines       33517    33598      +81     
  Branches     5570     5573       +3     
==========================================
- Hits        32444    32433      -11     
- Misses        845      926      +81     
- Partials      228      239      +11     

codecov[bot] avatar Jun 08 '23 15:06 codecov[bot]

Thanks for adding the RELEASE.md file!

Here's a preview of the changelog:


Operations over graphql-transport-ws now create the Context and perform validation on the worker Task, thus not blocking the websocket from accepting messages.

Here's the tweet text:

πŸ†• Release (next) is out! Thanks to @kristjanvalur for the PR πŸ‘

Get it here πŸ‘‰ https://strawberry.rocks/release/(next)

botberry avatar Jun 08 '23 15:06 botberry

Thanks for updating @kristjanvalur, still validating the changes :+1:

DoctorJohn avatar Jun 27 '23 14:06 DoctorJohn

CodSpeed Performance Report

Merging #2829 will not alter performance

Comparing mainframeindustries:kristjan/validate-in-task (e43aca8) with main (fc25e04)

Summary

βœ… 15 untouched benchmarks

codspeed-hq[bot] avatar Jul 19 '23 10:07 codspeed-hq[bot]

Hi @kristjanvalur, thanks for keeping this PR up to date! I promise I'll get to this soon-ish :D

patrick91 avatar Nov 08 '23 10:11 patrick91

No rush, just keeping things tidy :)

kristjanvalur avatar Nov 08 '23 17:11 kristjanvalur

PR is updated but I cannot see from the codecov that there is any missing coverage for my changes.

kristjanvalur avatar Sep 08 '24 12:09 kristjanvalur

This PR needs to be completely refactored because of the upstream changes. The "context" and "root value" are now created in a different place, long before the task is created. These really need to be evaluated in the context of the Task to not block the socket. I will attempt to re-factor this again.

kristjanvalur avatar Oct 13 '24 11:10 kristjanvalur

This PR needs to be completely refactored because of the upstream changes. The "context" and "root value" are now created in a different place, long before the task is created. These really need to be evaluated in the context of the Task to not block the socket. I will attempt to re-factor this again.

Hi KristjΓ‘n, thanks for bringing this up again!

During a brief discussion of this PR at PyconIT earlier this year, I realized that the strawberry core devs I talked to generally perceive get_context and get_root_value as lightweight methods. After recent refactors, both methods are only being called once per WebSocket connection.

Based on the assumption that these operations are lightweight, we were less concerned about get_context/get_root_value than the request validation mentioned in this PR's description. Feel free to split the request validation optimization in a separate PR so that we do not delay the merging of either part of this PR by pondering the other.

DoctorJohn avatar Oct 13 '24 16:10 DoctorJohn

Sounds good. I'll leave the context/root as they are and rework this to just do the validation.

kristjanvalur avatar Oct 13 '24 16:10 kristjanvalur

It appears that validation now happens in the task ,because the result_source is awaited inside the Task now. So presumably, validation now happens as part of that, in a separate Task. Since context is now created once for each connection, this leaves nothing left for this PR to do. All it could contribute is perhaps tests that validation does not block other messages for the connection. I'm inclined to simply close this.

kristjanvalur avatar Oct 13 '24 17:10 kristjanvalur

Actually, my tests as written for the old PR do indicate a discrepancy in validation handling for queries vs subscriptions. I'll create a new PR with just the tests, showing the problem, without proposing a solution. see #3671. Please have a look at this and give me your opinion.

kristjanvalur avatar Oct 13 '24 19:10 kristjanvalur

By the way, speaking of "context" being created once for each WS connection, I want to draw your attention to this bug: #1754

kristjanvalur avatar Oct 16 '24 09:10 kristjanvalur

It appears that validation now happens in the task ,because the result_source is awaited inside the Task now. So presumably, validation now happens as part of that, in a separate Task. Since context is now created once for each connection, this leaves nothing left for this PR to do. All it could contribute is perhaps tests that validation does not block other messages for the connection. I'm inclined to simply close this.

Thanks for verifying! It looks like this was changed when extension support for subscriptions was added. Let's close this PR then.

Actually, my tests as written for the old PR do indicate a discrepancy in validation handling for queries vs subscriptions. I'll create a new PR with just the tests, showing the problem, without proposing a solution. see https://github.com/strawberry-graphql/strawberry/pull/3671. Please have a look at this and give me your opinion.

Thank you so much for highlighting that. I'll check the specs and the PR introducing this discrepancy again. It looks like something slipped through the review and had no proper tests.

By the way, speaking of "context" being created once for each WS connection, I want to draw your attention to this bug: https://github.com/strawberry-graphql/strawberry/issues/1754

:+1: Currently reading through it.

DoctorJohn avatar Oct 21 '24 15:10 DoctorJohn