Skip to content
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

Resolvers keep running even after one of them throws/rejects - consider Promise.allSettled? #2974

Open
olsavmic opened this issue Mar 18, 2021 · 9 comments

Comments

@olsavmic
Copy link

Hi,
I recently came across this issue while trying to create a DB transaction per request.

The reason for using a DB transaction per request (which means 1 connection per client) is to keep the returned data consistent (ISOLATION READ COMMITED) as with increased traffic some inconsistencies started to occur on certain queries.

The second reason is having more control over the db connections to support load balancing with dynamic number of read replicas (as the only available solution unfortunately does not support connection pool). However I suppose this can be solved with some effort.

The problem is that when one of the resolvers fails with error (which is not a casual case but happens sometimes), other resolvers keep running. However I need to release the db connection before I send the response which sometimes happens before the rest of resolvers finishes (most of them are data loaders which makes the problem more obvious as the default behaviour is to wait for the next tick until the batch operation runs).

The problem could be resolved by using Promise.allSettled instead of Promise.all. I can't come up with any problem this change could cause except longer time till response in case of error.

Can you please correct me if I'm mistaken or consider this change? Or maybe transactional processing of resolvers is a bad idea in general (although I don't see any reason except the performance gain from using multiple connections per request)

Thanks a lot!

@IvanGoncharov IvanGoncharov added this to the 16.0.0-alpha.1 milestone Apr 4, 2021
@IvanGoncharov
Copy link
Member

@olsavmic I think it's a more general issue than DB transactions since it will affect any resources with reference counting.
Also, it can potentially DDoS problem, if you can find a request that fails fast but provokes a lot of memory allocation referenced by long-running resolvers you can run out of memory on the server.

But we need to be extra careful with execute code to not affect performance or correctness.
So let's postpone this fix until we finish TS conversion and release it in the upcoming 16.0.0.

@olsavmic
Copy link
Author

olsavmic commented Apr 6, 2021

Good point, thank you!

@olsavmic
Copy link
Author

olsavmic commented Aug 8, 2021

Hi @IvanGoncharov, I see this issue in the 16.0.0-alpha.1 milestone which has already been released. Is it still planned for the v16 or did you come over to some issues with this change?

Thanks a lot! :)

@hamzahamidi
Copy link

This feature is useful when the tasks are not dependent on each other.

@olsavmic
Copy link
Author

@hamzahamidi Can you elaborate on this? I can't think of such situation as I'm not saying to run these resolvers in sequence but rather just way for all resolvers to finish before sending a response which allows for proper resource cleanup and prevents possible DDoS as @IvanGoncharov stated.

@yaacovCR
Copy link
Contributor

@IvanGoncharov can we consider this for v16?

yaacovCR added a commit to yaacovCR/graphql-js that referenced this issue Oct 19, 2021
yaacovCR added a commit to yaacovCR/graphql-js that referenced this issue Oct 19, 2021
...and instead mutate original object

Also addresses:
graphql#2974
yaacovCR added a commit to yaacovCR/graphql-js that referenced this issue Oct 19, 2021
...and instead mutate original object

Also addresses:
graphql#2974
yaacovCR added a commit to yaacovCR/graphql-js that referenced this issue Oct 21, 2021
...and instead mutate original object

Also addresses:
graphql#2974
yaacovCR added a commit to yaacovCR/graphql-js that referenced this issue Oct 22, 2021
...and instead mutate original object

Also addresses:
graphql#2974
yaacovCR added a commit to yaacovCR/graphql-js that referenced this issue Oct 22, 2021
* Avoid Promise.all

...and instead mutate original object

Also addresses:
graphql#2974

* add changeset
@yaacovCR
Copy link
Contributor

Released in graphql executor 0.0.7 see above links

@IvanGoncharov IvanGoncharov removed this from the 16.0.0-alpha.1 milestone Nov 28, 2021
@charsleysa
Copy link

We ran into this issue and it was causing problems with our dependency injection as we didn't expect the behaviour of graphql to be continue processing after returning an error result.

@yaacovCR
Copy link
Contributor

yaacovCR commented Nov 5, 2024

This is partially handled by #4267

The execution tree will end, although the response will be returned first.

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

No branches or pull requests

5 participants