-
Notifications
You must be signed in to change notification settings - Fork 257
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds debug query planner option to skip query planning for a single s…
…ubgraph (#2441) This commit adds a new option to the query planner config that, when used and when the supergraph is built from only a single subgraph, skip the query planning algorithm and instead generates a single fetch (to the one subgraph) that directly uses the gateway "input" query. This option is disabled by default and marked as a "debug" option as it is a bit of a hack and so we're not suggesting committing to supporting it forever. But it is easy enough to have now and can be convenient at least for testing/debugging. Note in particular that, when used, some of the features enabled by the query planner (for instance `@defer`) cannot be enabled. The option will also stop having any effect as soon as another subgraph is added, not matter what that 2nd subgraph contains.
- Loading branch information
Sylvain Lebresne
authored
Mar 8, 2023
1 parent
2a35f55
commit ade7ceb
Showing
8 changed files
with
269 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
"@apollo/query-planner": minor | ||
"@apollo/gateway": minor | ||
--- | ||
|
||
Adds debug/testing query planner options (`debug.bypassPlannerForSingleSubgraph`) to bypass the query planning | ||
process for federated supergraph having only a single subgraph. The option is disabled by default, is not recommended | ||
for production, and is not supported (it may be removed later). It is meant for debugging/testing purposes. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
gateway-js/src/__tests__/gateway/queryPlannerConfig.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import gql from 'graphql-tag'; | ||
import { startSubgraphsAndGateway, Services } from './testUtils' | ||
|
||
let services: Services; | ||
|
||
afterEach(async () => { | ||
if (services) { | ||
await services.stop(); | ||
} | ||
}); | ||
|
||
describe('`debug.bypassPlannerForSingleSubgraph` config', () => { | ||
const subgraph = { | ||
name: 'A', | ||
url: 'https://A', | ||
typeDefs: gql` | ||
type Query { | ||
a: A | ||
} | ||
type A { | ||
b: B | ||
} | ||
type B { | ||
x: Int | ||
y: String | ||
} | ||
`, | ||
resolvers: { | ||
Query: { | ||
a: () => ({ | ||
b: { | ||
x: 1, | ||
y: 'foo', | ||
} | ||
}), | ||
} | ||
} | ||
}; | ||
|
||
const query = ` | ||
{ | ||
a { | ||
b { | ||
x | ||
y | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const expectedResult = ` | ||
Object { | ||
"data": Object { | ||
"a": Object { | ||
"b": Object { | ||
"x": 1, | ||
"y": "foo", | ||
}, | ||
}, | ||
}, | ||
} | ||
`; | ||
|
||
it('is disabled by default', async () => { | ||
services = await startSubgraphsAndGateway([subgraph]); | ||
|
||
const response = await services.queryGateway(query); | ||
const result = await response.json(); | ||
expect(result).toMatchInlineSnapshot(expectedResult); | ||
|
||
const queryPlanner = services.gateway.__testing().queryPlanner!; | ||
// If the query planner is genuinely used, we shoud have evaluated 1 plan. | ||
expect(queryPlanner.lastGeneratedPlanStatistics()?.evaluatedPlanCount).toBe(1); | ||
}); | ||
|
||
it('works when enabled', async () => { | ||
services = await startSubgraphsAndGateway( | ||
[subgraph], | ||
{ | ||
gatewayConfig: { | ||
queryPlannerConfig: { | ||
debug: { | ||
bypassPlannerForSingleSubgraph: true, | ||
} | ||
} | ||
} | ||
} | ||
); | ||
|
||
const response = await services.queryGateway(query); | ||
const result = await response.json(); | ||
expect(result).toMatchInlineSnapshot(expectedResult); | ||
|
||
const queryPlanner = services.gateway.__testing().queryPlanner!; | ||
// The `bypassPlannerForSingleSubgraph` doesn't evaluate anything. It's use is the only case where `evaluatedPlanCount` can be 0. | ||
expect(queryPlanner.lastGeneratedPlanStatistics()?.evaluatedPlanCount).toBe(0); | ||
}); | ||
}); | ||
|
Oops, something went wrong.