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

feat: @requires directive on different services as gateway #470

Merged

Conversation

simone-sanfratello
Copy link
Contributor

@simone-sanfratello simone-sanfratello commented Apr 27, 2021

Following #456, it provide support for @requires directive to work properly on gateway on different services


Using benchmarks from https://github.com/mercurius-js/auth/tree/main/bench

this branch

==============================
= Normal Mode                =
==============================
Running 10s test @ http://localhost:3000/graphql
100 connections

┌─────────┬──────┬──────┬───────┬───────┬─────────┬─────────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%   │ Avg     │ Stdev   │ Max   │
├─────────┼──────┼──────┼───────┼───────┼─────────┼─────────┼───────┤
│ Latency │ 4 ms │ 4 ms │ 6 ms  │ 11 ms │ 4.58 ms │ 2.26 ms │ 89 ms │
└─────────┴──────┴──────┴───────┴───────┴─────────┴─────────┴───────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
│ Req/Sec   │ 11231   │ 11231   │ 20079   │ 20319   │ 19160.37 │ 2523.42 │ 11228   │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
│ Bytes/Sec │ 5.91 MB │ 5.91 MB │ 10.6 MB │ 10.7 MB │ 10.1 MB  │ 1.33 MB │ 5.91 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘

Req/Bytes counts sampled once per second.

211k requests in 11.03s, 111 MB read
===============================
= Gateway Mode                =
===============================
Running 10s test @ http://localhost:3000/graphql
100 connections

┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev    │ Max    │
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
│ Latency │ 27 ms │ 28 ms │ 55 ms │ 73 ms │ 30.45 ms │ 13.14 ms │ 269 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
┌───────────┬────────┬────────┬─────────┬─────────┬─────────┬────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min    │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼────────┼────────┤
│ Req/Sec   │ 1284   │ 1284   │ 3509    │ 3577    │ 3229.1  │ 658.7  │ 1284   │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼────────┼────────┤
│ Bytes/Sec │ 450 kB │ 450 kB │ 1.23 MB │ 1.25 MB │ 1.13 MB │ 231 kB │ 449 kB │
└───────────┴────────┴────────┴─────────┴─────────┴─────────┴────────┴────────┘

Req/Bytes counts sampled once per second.

36k requests in 11.02s, 12.4 MB read

master branch

==============================
= Normal Mode                =
==============================
Running 10s test @ http://localhost:3000/graphql
100 connections

┌─────────┬──────┬──────┬───────┬───────┬─────────┬────────┬───────┐
│ Stat    │ 2.5% │ 50%  │ 97.5% │ 99%   │ Avg     │ Stdev  │ Max   │
├─────────┼──────┼──────┼───────┼───────┼─────────┼────────┼───────┤
│ Latency │ 4 ms │ 4 ms │ 6 ms  │ 13 ms │ 4.58 ms │ 2.3 ms │ 89 ms │
└─────────┴──────┴──────┴───────┴───────┴─────────┴────────┴───────┘
┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
│ Stat      │ 1%      │ 2.5%    │ 50%     │ 97.5%   │ Avg      │ Stdev   │ Min     │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
│ Req/Sec   │ 11159   │ 11159   │ 19983   │ 20687   │ 19107.28 │ 2585.38 │ 11157   │
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
│ Bytes/Sec │ 5.87 MB │ 5.87 MB │ 10.5 MB │ 10.9 MB │ 10 MB    │ 1.36 MB │ 5.87 MB │
└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘

Req/Bytes counts sampled once per second.

210k requests in 11.02s, 111 MB read
===============================
= Gateway Mode                =
===============================
Running 10s test @ http://localhost:3000/graphql
100 connections

┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
│ Stat    │ 2.5%  │ 50%   │ 97.5% │ 99%   │ Avg      │ Stdev    │ Max    │
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
│ Latency │ 26 ms │ 28 ms │ 53 ms │ 76 ms │ 30.82 ms │ 15.51 ms │ 309 ms │
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
┌───────────┬────────┬────────┬─────────┬─────────┬─────────┬────────┬────────┐
│ Stat      │ 1%     │ 2.5%   │ 50%     │ 97.5%   │ Avg     │ Stdev  │ Min    │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼────────┼────────┤
│ Req/Sec   │ 1290   │ 1290   │ 3443    │ 3617    │ 3190.9  │ 673.72 │ 1290   │
├───────────┼────────┼────────┼─────────┼─────────┼─────────┼────────┼────────┤
│ Bytes/Sec │ 452 kB │ 452 kB │ 1.21 MB │ 1.27 MB │ 1.12 MB │ 236 kB │ 452 kB │
└───────────┴────────┴────────┴─────────┴─────────┴─────────┴────────┴────────┘

Req/Bytes counts sampled once per second.

32k requests in 10.03s, 11.2 MB read

@simone-sanfratello simone-sanfratello marked this pull request as draft April 27, 2021 09:31
Copy link
Collaborator

@simoneb simoneb left a comment

Choose a reason for hiding this comment

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

A few minor comments but overall LGTM. Good stuff!

lib/federation.js Outdated Show resolved Hide resolved
lib/federation.js Show resolved Hide resolved
lib/gateway/service-map.js Show resolved Hide resolved
lib/gateway/service-map.js Outdated Show resolved Hide resolved
test/gateway/request.js Outdated Show resolved Hide resolved
if (!selectedFields.includes(field.name.value)) {
continue
}
const directive = field.directives.find(d => d.name.value === 'requires')
Copy link
Collaborator

Choose a reason for hiding this comment

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

can this be null for some reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm writing a test case

Copy link
Contributor Author

Choose a reason for hiding this comment

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

can't find a case. help?

Copy link
Contributor

@jonnydgreen jonnydgreen Apr 27, 2021

Choose a reason for hiding this comment

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

Looking at the logic, any non-external field defined on the external type and containing a directive that isn't requires should get you the test case.

For example:

Schema:

directive @custom on OBJECT | FIELD_DEFINITION

type Size @key(fields: "id") {
  id: Int!
  cpus: Int!
  memory: Int!
}

type Region @key(fields: "id") {
  id: Int!
  city: String!
}

type Metadata @key(fields: "id") {
  id: Int!
  description: String!
}

extend type Host @key(fields: "id") {
  id: Int! @external
  size: Int! @external
  region: Int! @external
  # Field defined here with directive that isn't `requires`
  metadata: Metadata! @custom
  sizeData: Size! @requires(fields: "size")
  regionData: Region! @requires(fields: "region")
}

Query:

query {
  hosts {
    name
    sizeData {
      cpus
    }
    metadata {
      description
    }
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

many thanks @jonnydgreen !

Copy link
Collaborator

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

This implementation looks good to me. Waiting for @PabloSzx @PacoDu @jonnydgreen to take a look.

bench/gateway-without-auth.js Outdated Show resolved Hide resolved
Copy link
Contributor

@jonnydgreen jonnydgreen left a comment

Choose a reason for hiding this comment

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

Looks good to me, nothing more to add than what's already been said!

bench/normal.js Outdated Show resolved Hide resolved
lib/util.js Outdated Show resolved Hide resolved
lib/util.js Outdated Show resolved Hide resolved
Simone Sanfratello and others added 5 commits April 27, 2021 17:37
Co-authored-by: Matteo Collina <matteo.collina@gmail.com>
Co-authored-by: Matteo Collina <matteo.collina@gmail.com>
@simone-sanfratello simone-sanfratello marked this pull request as ready for review April 27, 2021 15:50
Copy link
Collaborator

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

lgtm

@jonnydgreen jonnydgreen self-requested a review April 27, 2021 16:35
Copy link
Contributor

@jonnydgreen jonnydgreen left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Contributor

@PacoDu PacoDu left a comment

Choose a reason for hiding this comment

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

LGTM

tho I do not understand why the windows test CI does not reach 100% coverage but the linux one does

ERROR: Coverage for lines (98.88%) does not meet global threshold (100%)
ERROR: Coverage for functions (99.19%) does not meet global threshold (100%)
ERROR: Coverage for branches (98.82%) does not meet global threshold (100%)
ERROR: Coverage for statements (98.91%) does not meet global threshold (100%)
--------------------------------------|---------|----------|---------|---------|-------------------
File                                  | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------------------------------|---------|----------|---------|---------|-------------------
All files                             |   98.91 |    98.82 |   99.19 |   98.88 |                   
 mercurius                            |   99.65 |    98.51 |     100 |   99.65 |                   
  index.js                            |   99.65 |    98.51 |     100 |   99.65 | 197               
 mercurius/lib                        |   99.41 |    99.28 |   98.88 |   99.39 |                   
  errors.js                           |     100 |      100 |     100 |     100 |                   
  federation.js                       |     100 |      100 |     100 |     100 |                   
  gateway.js                          |   96.38 |    96.61 |   92.59 |   96.24 | 357,364,367-369   
  handlers.js                         |     100 |      100 |     100 |     100 |                   
  hooks.js                            |     100 |    97.73 |     100 |     100 | 52                
  persistedQueryDefaults.js           |     100 |      100 |     100 |     100 |                   
  queryDepth.js                       |     100 |      100 |     100 |     100 |                   
  routes.js                           |     100 |      100 |     100 |     100 |                   
  subscriber.js                       |     100 |      100 |     100 |     100 |                   
  subscription-client.js              |     100 |      100 |     100 |     100 |                   
  subscription-connection.js          |     100 |      100 |     100 |     100 |                   
  subscription-protocol.js            |     100 |      100 |     100 |     100 |                   
  subscription.js                     |     100 |      100 |     100 |     100 |                   
  symbols.js                          |     100 |      100 |     100 |     100 |                   
  util.js                             |     100 |      100 |     100 |     100 |                   
 mercurius/lib/federation             |     100 |      100 |     100 |     100 |                   
  compositionRules.js                 |     100 |      100 |     100 |     100 |                   
 mercurius/lib/gateway                |   96.77 |     97.9 |     100 |   96.61 |                   
  make-resolver.js                    |     100 |      100 |     100 |     100 |                   
  request.js                          |     100 |      100 |     100 |     100 |                   
  service-map.js                      |   90.91 |    91.18 |     100 |   90.91 | 92-97,141-147     
 mercurius/tap-snapshots/test         |     100 |      100 |     100 |     100 |                   
  errors.js.test.cjs                  |     100 |      100 |     100 |     100 |                   
  federation.js.test.cjs              |     100 |      100 |     100 |     100 |                   
  reply-decorator.js.test.cjs         |     100 |      100 |     100 |     100 |                   
  routes.js.test.cjs                  |     100 |      100 |     100 |     100 |                   
 mercurius/tap-snapshots/test/gateway |     100 |      100 |     100 |     100 |                   
  remote-services.js.test.cjs         |     100 |      100 |     100 |     100 |                   
--------------------------------------|---------|----------|---------|---------|-------------------

@PabloSzx
Copy link
Member

LGTM

tho I do not understand why the windows test CI does not reach 100% coverage but the linux one does

ERROR: Coverage for lines (98.88%) does not meet global threshold (100%)
ERROR: Coverage for functions (99.19%) does not meet global threshold (100%)
ERROR: Coverage for branches (98.82%) does not meet global threshold (100%)
ERROR: Coverage for statements (98.91%) does not meet global threshold (100%)
--------------------------------------|---------|----------|---------|---------|-------------------
File                                  | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
--------------------------------------|---------|----------|---------|---------|-------------------
All files                             |   98.91 |    98.82 |   99.19 |   98.88 |                   
 mercurius                            |   99.65 |    98.51 |     100 |   99.65 |                   
  index.js                            |   99.65 |    98.51 |     100 |   99.65 | 197               
 mercurius/lib                        |   99.41 |    99.28 |   98.88 |   99.39 |                   
  errors.js                           |     100 |      100 |     100 |     100 |                   
  federation.js                       |     100 |      100 |     100 |     100 |                   
  gateway.js                          |   96.38 |    96.61 |   92.59 |   96.24 | 357,364,367-369   
  handlers.js                         |     100 |      100 |     100 |     100 |                   
  hooks.js                            |     100 |    97.73 |     100 |     100 | 52                
  persistedQueryDefaults.js           |     100 |      100 |     100 |     100 |                   
  queryDepth.js                       |     100 |      100 |     100 |     100 |                   
  routes.js                           |     100 |      100 |     100 |     100 |                   
  subscriber.js                       |     100 |      100 |     100 |     100 |                   
  subscription-client.js              |     100 |      100 |     100 |     100 |                   
  subscription-connection.js          |     100 |      100 |     100 |     100 |                   
  subscription-protocol.js            |     100 |      100 |     100 |     100 |                   
  subscription.js                     |     100 |      100 |     100 |     100 |                   
  symbols.js                          |     100 |      100 |     100 |     100 |                   
  util.js                             |     100 |      100 |     100 |     100 |                   
 mercurius/lib/federation             |     100 |      100 |     100 |     100 |                   
  compositionRules.js                 |     100 |      100 |     100 |     100 |                   
 mercurius/lib/gateway                |   96.77 |     97.9 |     100 |   96.61 |                   
  make-resolver.js                    |     100 |      100 |     100 |     100 |                   
  request.js                          |     100 |      100 |     100 |     100 |                   
  service-map.js                      |   90.91 |    91.18 |     100 |   90.91 | 92-97,141-147     
 mercurius/tap-snapshots/test         |     100 |      100 |     100 |     100 |                   
  errors.js.test.cjs                  |     100 |      100 |     100 |     100 |                   
  federation.js.test.cjs              |     100 |      100 |     100 |     100 |                   
  reply-decorator.js.test.cjs         |     100 |      100 |     100 |     100 |                   
  routes.js.test.cjs                  |     100 |      100 |     100 |     100 |                   
 mercurius/tap-snapshots/test/gateway |     100 |      100 |     100 |     100 |                   
  remote-services.js.test.cjs         |     100 |      100 |     100 |     100 |                   
--------------------------------------|---------|----------|---------|---------|-------------------

the gateway schema poll interval is failing periodically 😞 I've been re-runing the actions for them to pass

@mcollina mcollina merged commit bc83aad into mercurius-js:master Apr 28, 2021
@mcollina
Copy link
Collaborator

@PabloSzx we should really refactor those tests. Maybe open a an issue or a PR?

@jonnydgreen
Copy link
Contributor

Happy to help out with this if you need as the remote-services.js tests take a long time to run as well which would be great to sort at the same time!

@mcollina
Copy link
Collaborator

go for it Jonny!

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.

6 participants