Skip to content

Conversation

@JoviDeCroock
Copy link
Member

This is an alternative approach to removing our instanceof check, when we detect a mismatched version of GraphQL we throw an error regardless of us being in development or production. This is justified because multiple GraphQL version will lead to weird behaviour either way, rather than embedding the whole string we link to our docs where the user can find steps for pnpm, ... we can keep expanding this.

@JoviDeCroock JoviDeCroock requested a review from a team as a code owner February 16, 2025 11:07
@github-actions
Copy link

Hi @JoviDeCroock, I'm @github-actions bot happy to help you with this PR 👋

Supported commands

Please post this commands in separate comments and only one per comment:

  • @github-actions run-benchmark - Run benchmark comparing base and merge commits for this PR
  • @github-actions publish-pr-on-npm - Build package from this PR and publish it on NPM

@JoviDeCroock JoviDeCroock force-pushed the instance-of-alternative branch from ff49b34 to bf8ebc5 Compare February 16, 2025 11:10
@JoviDeCroock JoviDeCroock added PR: polish 💅 PR doesn't change public API or any observed behaviour PR: breaking change 💥 implementation requires increase of "major" version number and removed PR: polish 💅 PR doesn't change public API or any observed behaviour labels Feb 16, 2025
}
}
return false;
}
Copy link
Member

Choose a reason for hiding this comment

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

I think this is a really hot path, are we sure we want to add more logic to it in production?

Copy link
Member Author

@JoviDeCroock JoviDeCroock Feb 16, 2025

Choose a reason for hiding this comment

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

The benchmarks showed no signs of serious regressions

found 0 vulnerabilities
⏱   Recreate a GraphQLSchema
  2 tests completed.

  local x 1,053 ops/sec ±1.82% x 453 KB/op (13 runs sampled)
  HEAD  x 1,064 ops/sec ±0.23% x 453 KB/op (12 runs sampled)

⏱   Build Schema from AST
  2 tests completed.

  local x 173 ops/sec ±0.31% x 3.75 MB/op (9 runs sampled)
  HEAD  x 172 ops/sec ±0.20% x 3.75 MB/op (11 runs sampled)

⏱   Build Schema from Introspection
  2 tests completed.

  local x 183 ops/sec ±0.20% x 3.84 MB/op (11 runs sampled)
  HEAD  x 183 ops/sec ±0.47% x 3.84 MB/op (12 runs sampled)

⏱   Execute Introspection Query
  2 tests completed.

  local x 62.99 ops/sec ±2.58% x 30.31 MB/op (5 runs sampled)
  HEAD  x 63.56 ops/sec ±0.33% x 30.31 MB/op (5 runs sampled)

⏱   Execute Asynchronous List Field
  2 tests completed.

  local x 2,996 ops/sec ±0.37% x 925 KB/op (31 runs sampled)
  HEAD  x 2,981 ops/sec ±0.53% x 925 KB/op (31 runs sampled)

⏱   Execute Async Iterable List Field
  2 tests completed.

  local x 2,566 ops/sec ±0.90% x 686 KB/op (30 runs sampled)
  HEAD  x 2,561 ops/sec ±0.79% x 687 KB/op (31 runs sampled)

⏱   Execute Synchronous List Field
  2 tests completed.

  local x 5,941 ops/sec ±0.63% x 188 KB/op (33 runs sampled)
  HEAD  x 5,926 ops/sec ±0.78% x 188 KB/op (31 runs sampled)

⏱   Parse introspection query
  2 tests completed.

  local x 16,738 ops/sec ±0.13% x 55.93 KB/op (16 runs sampled)
  HEAD  x 16,747 ops/sec ±0.21% x 55.93 KB/op (18 runs sampled)

⏱   Many repeated fields
  2 tests completed.

  local x 88.62 ops/sec ±0.79% x 6.01 MB/op (9 runs sampled)
  HEAD  x 88.57 ops/sec ±1.01% x 6.06 MB/op (8 runs sampled)

⏱   Validate Introspection Query
  2 tests completed.

  local x 1,128 ops/sec ±1.48% x 417 KB/op (9 runs sampled)
  HEAD  x 1,131 ops/sec ±1.57% x 417 KB/op (5 runs sampled)

⏱   Validate Invalid Query
  2 tests completed.

  local x 861 ops/sec ±0.17% x 553 KB/op (8 runs sampled)
  HEAD  x 860 ops/sec ±0.14% x 553 KB/op (10 runs sampled)

⏱   Validate SDL Document
  2 tests completed.

  local x 122 ops/sec ±0.75% x 3.34 MB/op (5 runs sampled)
  HEAD  x 122 ops/sec ±0.14% x 3.34 MB/op (5 runs sampled)

⏱   Visit all AST nodes
  2 tests completed.

  local x 416 ops/sec ±0.84% x 2.07 MB/op (16 runs sampled)
  HEAD  x 417 ops/sec ±0.32% x 2.07 MB/op (16 runs sampled)

⏱   Visit all AST nodes in parallel
  2 tests completed.

  local x  43.7 ops/sec ±0.76% x 2.21 MB/op (5 runs sampled)
  HEAD  x 43.97 ops/sec ±0.37% x 2.21 MB/op (5 runs sampled)

Copy link
Member Author

@JoviDeCroock JoviDeCroock Feb 16, 2025

Choose a reason for hiding this comment

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

The alternative is that we completely scrap instanceof and actually make multiple versions of graphql work alongside each other. The process.env check has caused so much grievances.

My main goal is to move v17 to beta/release-candidate versions

Copy link
Member

Choose a reason for hiding this comment

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

actually make multiple versions of graphql work alongside each other

I, personally, think this would be a mistake. What if one supports oneof and the other doesn't? Or stream/defer? Fragment arguments?

The benchmarks showed no signs of serious regressions

Great; glad we found my concerns unwarranted :) Carry on :)

Copy link
Contributor

Choose a reason for hiding this comment

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

On my machine, I get a performance regression with this change:

image

Copy link
Contributor

Choose a reason for hiding this comment

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

Running the benchmark github action...

: value.constructor?.name;
if (className === valueClassName) {
throw new Error(
`Multiple GraphQL instances detected, Cannot use ${className} from another module or realm. Read more at https://graphql-js.org/errors#1`,
Copy link
Member

Choose a reason for hiding this comment

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

I recommend that you don't use monotonically increasing error numbers as it will cause conflicts when you have multiple branches being worked on concurrently and introducing new errors. I also recommend that you use a page per error otherwise the singular error page could get overwhelming (and fixing it later may break existing links in deployed applications).

At Graphile we use our "errored" domain for errors, e.g. https://err.red/gev2 - the first character indicates which website it goes to (g for https://grafast.org/errors/) and the ev2 is a code for the error which links to the relevant page under that. This further allows adding sub-anchors such as https://err.red/gev2#stream.

@JoviDeCroock JoviDeCroock force-pushed the instance-of-alternative branch from bf8ebc5 to e7802b7 Compare February 16, 2025 12:27
@yaacovCR

This comment has been minimized.

@github-actions
Copy link

@github-actions run-benchmark

@yaacovCR

Benchmark output

[email protected] benchmark
node --loader ts-node/esm resources/benchmark.ts --revs HEAD BASE

🍳 Preparing HEAD...

added 526 packages, and audited 527 packages in 3s

173 packages are looking for funding
run npm fund for details

found 0 vulnerabilities

[email protected] build:npm
node --loader ts-node/esm resources/build-npm.ts

./npmDist
*.mjs.map x149 | 1304.14 KB
*.js.map x149 | 1303.00 KB
*.js x149 | 770.36 KB
*.mjs x149 | 649.25 KB
*.d.ts x150 | 233.71 KB
README.md | 5.33 KB
LICENSE | 1.05 KB
package.json | 0.75 KB

     Total |    4.17 MB

./npmEsmDist
*.js.map x149 | 1304.14 KB
*.js x149 | 648.71 KB
*.d.ts x150 | 233.71 KB
README.md | 5.33 KB
package.json | 1.06 KB
LICENSE | 1.05 KB

    Total |    2.14 MB

added 1 package, and audited 2 packages in 674ms

found 0 vulnerabilities
🍳 Preparing BASE...

added 526 packages, and audited 527 packages in 3s

173 packages are looking for funding
run npm fund for details

found 0 vulnerabilities

[email protected] build:npm
node --loader ts-node/esm resources/build-npm.ts

./npmDist
*.mjs.map x149 | 1305.73 KB
*.js.map x149 | 1304.56 KB
*.js x149 | 771.42 KB
*.mjs x149 | 650.29 KB
*.d.ts x150 | 233.71 KB
README.md | 5.33 KB
LICENSE | 1.05 KB
package.json | 0.75 KB

     Total |    4.17 MB

./npmEsmDist
*.js.map x149 | 1305.73 KB
*.js x149 | 649.74 KB
*.d.ts x150 | 233.71 KB
README.md | 5.33 KB
package.json | 1.06 KB
LICENSE | 1.05 KB

    Total |    2.15 MB

added 1 package, and audited 2 packages in 658ms

found 0 vulnerabilities
⏱ Recreate a GraphQLSchema
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[31m608�[0m ops/sec �[90m±�[0m�[32m0.56�[0m�[36m%�[0m�[90m x �[0m453 KB/op�[90m (13 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m992�[0m ops/sec �[90m±�[0m�[32m0.89�[0m�[36m%�[0m�[90m x �[0m453 KB/op�[90m (14 runs sampled)�[0m

⏱ Build Schema from AST
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[33m87.83�[0m ops/sec �[90m±�[0m�[31m8.34�[0m�[36m%�[0m�[90m x �[0m3.77 MB/op�[90m (7 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m99.38�[0m ops/sec �[90m±�[0m�[33m4.17�[0m�[36m%�[0m�[90m x �[0m3.77 MB/op�[90m (6 runs sampled)�[0m

⏱ Build Schema from Introspection
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[33m94.13�[0m ops/sec �[90m±�[0m�[32m1.29�[0m�[36m%�[0m�[90m x �[0m3.82 MB/op�[90m (10 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m 112�[0m ops/sec �[90m±�[0m�[32m1.06�[0m�[36m%�[0m�[90m x �[0m3.84 MB/op�[90m (10 runs sampled)�[0m

⏱ Execute Introspection Query
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[31m25.43�[0m ops/sec �[90m±�[0m�[32m0.62�[0m�[36m%�[0m�[90m x �[0m30.3 MB/op�[90m (5 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m 34.5�[0m ops/sec �[90m±�[0m�[33m2.23�[0m�[36m%�[0m�[90m x �[0m30.3 MB/op�[90m (5 runs sampled)�[0m

⏱ Execute Asynchronous List Field
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[33m1,291�[0m ops/sec �[90m±�[0m�[32m0.47�[0m�[36m%�[0m�[90m x �[0m926 KB/op�[90m (20 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m1,595�[0m ops/sec �[90m±�[0m�[32m0.63�[0m�[36m%�[0m�[90m x �[0m926 KB/op�[90m (21 runs sampled)�[0m

⏱ Execute Async Iterable List Field
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[31m1,093�[0m ops/sec �[90m±�[0m�[32m1.83�[0m�[36m%�[0m�[90m x �[0m687 KB/op�[90m (18 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m1,739�[0m ops/sec �[90m±�[0m�[32m0.61�[0m�[36m%�[0m�[90m x �[0m687 KB/op�[90m (18 runs sampled)�[0m

⏱ Execute Synchronous List Field
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[31m3,094�[0m ops/sec �[90m±�[0m�[32m0.46�[0m�[36m%�[0m�[90m x �[0m187 KB/op�[90m (19 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m5,604�[0m ops/sec �[90m±�[0m�[32m0.74�[0m�[36m%�[0m�[90m x �[0m187 KB/op�[90m (21 runs sampled)�[0m

⏱ Parse introspection query
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[32m8,686�[0m ops/sec �[90m±�[0m�[32m0.41�[0m�[36m%�[0m�[90m x �[0m55.73 KB/op�[90m (12 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m8,694�[0m ops/sec �[90m±�[0m�[32m0.37�[0m�[36m%�[0m�[90m x �[0m55.73 KB/op�[90m (11 runs sampled)�[0m

⏱ Many repeated fields
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[31m51.88�[0m ops/sec �[90m±�[0m�[32m0.36�[0m�[36m%�[0m�[90m x �[0m6.02 MB/op�[90m (8 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m98.98�[0m ops/sec �[90m±�[0m�[32m0.40�[0m�[36m%�[0m�[90m x �[0m6.02 MB/op�[90m (11 runs sampled)�[0m

⏱ Validate Introspection Query
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[33m604�[0m ops/sec �[90m±�[0m�[32m0.51�[0m�[36m%�[0m�[90m x �[0m412 KB/op�[90m (9 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m640�[0m ops/sec �[90m±�[0m�[32m0.80�[0m�[36m%�[0m�[90m x �[0m412 KB/op�[90m (7 runs sampled)�[0m

⏱ Validate Invalid Query
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[32m497�[0m ops/sec �[90m±�[0m�[32m0.64�[0m�[36m%�[0m�[90m x �[0m553 KB/op�[90m (5 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m500�[0m ops/sec �[90m±�[0m�[32m0.58�[0m�[36m%�[0m�[90m x �[0m553 KB/op�[90m (5 runs sampled)�[0m

⏱ Validate SDL Document
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[32m69.57�[0m ops/sec �[90m±�[0m�[33m2.42�[0m�[36m%�[0m�[90m x �[0m3.32 MB/op�[90m (5 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m72.26�[0m ops/sec �[90m±�[0m�[32m1.81�[0m�[36m%�[0m�[90m x �[0m3.32 MB/op�[90m (7 runs sampled)�[0m

⏱ Visit all AST nodes
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[32m256�[0m ops/sec �[90m±�[0m�[32m0.67�[0m�[36m%�[0m�[90m x �[0m2.07 MB/op�[90m (11 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m257�[0m ops/sec �[90m±�[0m�[32m0.53�[0m�[36m%�[0m�[90m x �[0m2.07 MB/op�[90m (13 runs sampled)�[0m

⏱ Visit all AST nodes in parallel
�[36m1�[0m tests completed.
�[36m2�[0m tests completed.

HEAD�[90m x �[0m�[32m28.19�[0m ops/sec �[90m±�[0m�[32m1.96�[0m�[36m%�[0m�[90m x �[0m2.21 MB/op�[90m (5 runs sampled)�[0m
�[32mBASE�[0m�[90m x �[0m�[32m28.31�[0m ops/sec �[90m±�[0m�[32m1.06�[0m�[36m%�[0m�[90m x �[0m2.21 MB/op�[90m (5 runs sampled)�[0m

@JoviDeCroock JoviDeCroock deleted the instance-of-alternative branch February 16, 2025 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: breaking change 💥 implementation requires increase of "major" version number

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants