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

CI Issue fixed and images optimised #413 resolved to #412 #415

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- name: Install and Build 🔧
run: |
npm install
npx prettier --check "**/*.{graphql,yml,json,md,sh,ts,tsx,js}"
npx prettier --check "**/*.{graphql,yml,json,md,sh,ts,tsx,js,css}"
npm run build

- name: Deploy 🚀
Expand Down
16 changes: 8 additions & 8 deletions blog/tailcall-n+1-working-2024-08-04.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ description: A deep dive into the implementation details of the N+1 tracker
slug: tailcall-n+1-identification-algorithm
---

As a developer working with GraphQL, you're likely familiar with the concept of N+1 issues, if not you should definitely check out our [N+1 guide](../docs/N+1.md).
As a developer working with GraphQL, you're likely familiar with the concept of N+1 issues. If not, you should definitely check out our [N+1 guide](https://tailcall.run/docs/N+1.md).

To summarize they occur when a GraphQL resolver is called multiple times for a single GraphQL request, leading a large set of requests upstream and overall a slower query execution. In this blog post, we'll dive into how Tailcall specifically identifies N+1 issues in GraphQL, and explore the algorithm and data structures used to detect these issues.
To summarize, N+1 issues occur when a GraphQL resolver is called multiple times for a single GraphQL request, leading to a large set of requests upstream and overall slower query execution. In this blog post, we'll dive into how Tailcall specifically identifies N+1 issues in GraphQL, and explore the algorithm and data structures used to detect these issues.

![Actual Usage Image](../static/images/blog/n+1-image-terminal.png)

Expand All @@ -21,20 +21,20 @@ Unlike a traditional GraphQL implementation where the resolvers are written by h

## The Algorithm

Tailcall reads your [configuration](../docs/configuration.mdx), parses it, and internally stores it in an efficient graph data-structure that resembles a `HashMap`. This allows `O(1)` access to a GraphQL type which represented as a node by its name. Once the graph data-structure is ready we make it go through a series of validators, one of them being the **N+1 tracker**.
Tailcall reads your [configuration](https://tailcall.run/docs/configuration.mdx), parses it, and internally stores it in an efficient graph data-structure that resembles a `HashMap`. This allows `O(1)` access to a GraphQL type which represented as a node by its name. Once the graph data-structure is ready we make it go through a series of validators, one of them being the **N+1 tracker**.

:::tip
To see the actual implementation you can check out the [tracker.rs](https://github.com/tailcallhq/tailcall/blob/main/src/core/config/npo/tracker.rs) implementation.
:::

We essentially use a Depth-First Search (DFS) algorithm starting at the root query and traversing all the connected nodes. The algorithm works as follows:

1. Initialize a to variables to track the currently traversed path and visited fields so that we can avoid cycles.
1. Initialize variables to track the currently traversed path and visited fields to avoid cycles.
2. Start at the root query and begin traversing the graph data structure.
3. For each field in the current node, check if it has a resolver and is not batched. We know if the node contains a resolver if that node has a [`@http`](../docs/directives.md#http-directive) or a [`@grpc`](../docs/directives.md#grpc-directive).
3. For each field in the current node, check if it has a resolver and is not batched. We know if the node contains a resolver if that node has a [`@http`](https://tailcall.run/docs/directives.md#http-directive) or a [`@grpc`](https://tailcall.run/docs/directives.md#grpc-directive).
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
3. For each field in the current node, check if it has a resolver and is not batched. We know if the node contains a resolver if that node has a [`@http`](https://tailcall.run/docs/directives.md#http-directive) or a [`@grpc`](https://tailcall.run/docs/directives.md#grpc-directive).
3. For each field in the current node, check if it has a resolver and is not batched. We know if the node contains a resolver if that node has a [`@http`](/docs/directives.md#http-directive) or a [`@grpc`](/docs/directives.md#grpc-directive).

Dont' use absolute URLs.


:::important
Tailcall supports powerful batching primitives and if a field uses a Batch API, then that resolver is whitelisted and dropped from the list of potential N+1 candidates.
Tailcall supports powerful batching primitives. If a field uses a Batch API, then that resolver is whitelisted and dropped from the list of potential N+1 candidates.
:::

4. If the field has a resolver and is not batched, and the current path contains a list, then the current path is added to the result.
Expand All @@ -44,7 +44,7 @@ Tailcall supports powerful batching primitives and if a field uses a Batch API,

## Performance

While starting, Tailcall automatically performs these validations and one of our users complained that it would take around 5 minutes to start the server for their configuration which was around 10,000 lines. The thing is finding N+1 issues is a complex dynamic-programming problem. All this while our team has been focused on [benchmarking](https://github.com/tailcallhq/graphql-benchmarks) and optimizing the runtime performance of the server. This was the first time perhaps that we were surprised to see such a degradation in performance. We quickly realized that this a dynamic programming problem and there are certain tricks to make such algorithms efficient for us it was basically two things —
When starting, Tailcall automatically performs these validations. One of our users reported that it took around 5 minutes to start the server for their configuration, which was around 10,000 lines. The thing is finding N+1 issues is a complex dynamic-programming problem. All this while our team has been focused on [benchmarking](https://github.com/tailcallhq/graphql-benchmarks) and optimizing the runtime performance of the server. This was the first time perhaps that we were surprised to see such a degradation in performance. We quickly realized that this a dynamic programming problem and there are certain tricks to make such algorithms efficient for us it was basically two things —

### 1. Memorization

Expand Down Expand Up @@ -113,4 +113,4 @@ Lastly to ensure that we are always correct and no N+1 issues go unidentified we
Hopefully, this gives some insight on how Tailcall identifies N+1 issues in your GraphQL configuration.

- If you think we can make our N+1 detection faster or better in some other way please help us improve by [contributing](https://github.com/tailcallhq/tailcall) 🙏
- If you find this interesting please spread the word 🙌
- If you find this interesting please spread the word 🙌
Binary file modified static/images/blog/github-npo-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/images/blog/n+1-image-terminal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading