@apollo/gateway 2.0.0-alpha.6 → 2.0.0-preview.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/dist/__generated__/graphqlTypes.d.ts +4 -0
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/dist/config.d.ts +8 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +4 -3
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -8
- package/dist/index.js.map +1 -1
- package/dist/schema-helper/index.js +5 -1
- package/dist/schema-helper/index.js.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.d.ts.map +1 -1
- package/dist/supergraphManagers/IntrospectAndCompose/index.js.map +1 -1
- package/dist/supergraphManagers/LegacyFetcher/index.d.ts +1 -1
- package/dist/supergraphManagers/LegacyFetcher/index.d.ts.map +1 -1
- package/dist/supergraphManagers/LegacyFetcher/index.js.map +1 -1
- package/dist/supergraphManagers/LocalCompose/index.d.ts +1 -1
- package/dist/supergraphManagers/LocalCompose/index.d.ts.map +1 -1
- package/dist/supergraphManagers/LocalCompose/index.js.map +1 -1
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts +4 -2
- package/dist/supergraphManagers/UplinkFetcher/index.d.ts.map +1 -1
- package/dist/supergraphManagers/UplinkFetcher/index.js +20 -4
- package/dist/supergraphManagers/UplinkFetcher/index.js.map +1 -1
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts +3 -2
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.d.ts.map +1 -1
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js +9 -3
- package/dist/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.js.map +1 -1
- package/package.json +8 -8
- package/src/__generated__/graphqlTypes.ts +11 -2
- package/src/__tests__/build-query-plan.feature +32 -16
- package/src/__tests__/buildQueryPlan.test.ts +51 -4
- package/src/__tests__/executeQueryPlan.test.ts +256 -1
- package/src/__tests__/execution-utils.ts +3 -2
- package/src/__tests__/gateway/executor.test.ts +1 -1
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +10 -4
- package/src/__tests__/gateway/reporting.test.ts +5 -0
- package/src/__tests__/gateway/supergraphSdl.test.ts +6 -4
- package/src/__tests__/integration/abstract-types.test.ts +6 -7
- package/src/__tests__/integration/complex-key.test.ts +1 -6
- package/src/__tests__/integration/configuration.test.ts +1 -12
- package/src/__tests__/integration/logger.test.ts +1 -1
- package/src/__tests__/integration/networkRequests.test.ts +1 -1
- package/src/__tests__/integration/value-types.test.ts +4 -4
- package/src/config.ts +13 -10
- package/src/core/__tests__/core.test.ts +8 -8
- package/src/executeQueryPlan.ts +4 -0
- package/src/index.ts +13 -7
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +1 -1
- package/src/supergraphManagers/IntrospectAndCompose/index.ts +1 -1
- package/src/supergraphManagers/LegacyFetcher/index.ts +1 -1
- package/src/supergraphManagers/LocalCompose/index.ts +1 -1
- package/src/supergraphManagers/UplinkFetcher/__tests__/loadSupergraphSdlFromStorage.test.ts +41 -0
- package/src/supergraphManagers/UplinkFetcher/index.ts +38 -19
- package/src/supergraphManagers/UplinkFetcher/loadSupergraphSdlFromStorage.ts +9 -1
|
@@ -31,7 +31,7 @@ describe('core v0.1', () => {
|
|
|
31
31
|
|
|
32
32
|
directive @tag(
|
|
33
33
|
name: String!
|
|
34
|
-
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
34
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
35
35
|
|
|
36
36
|
enum CacheControlScope {
|
|
37
37
|
PRIVATE
|
|
@@ -87,7 +87,7 @@ describe('core v0.1', () => {
|
|
|
87
87
|
|
|
88
88
|
directive @tag(
|
|
89
89
|
name: String!
|
|
90
|
-
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
90
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
91
91
|
|
|
92
92
|
enum CacheControlScope {
|
|
93
93
|
PRIVATE
|
|
@@ -124,7 +124,7 @@ describe('core v0.2', () => {
|
|
|
124
124
|
schema
|
|
125
125
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
126
126
|
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
127
|
-
@core(feature: "https://specs.apollo.dev/tag/v0.
|
|
127
|
+
@core(feature: "https://specs.apollo.dev/tag/v0.2") {
|
|
128
128
|
query: Query
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -151,7 +151,7 @@ describe('core v0.2', () => {
|
|
|
151
151
|
|
|
152
152
|
directive @tag(
|
|
153
153
|
name: String!
|
|
154
|
-
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
154
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
155
155
|
|
|
156
156
|
enum CacheControlScope {
|
|
157
157
|
PRIVATE
|
|
@@ -193,7 +193,7 @@ describe('core v0.2', () => {
|
|
|
193
193
|
schema
|
|
194
194
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
195
195
|
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
196
|
-
@core(feature: "https://specs.apollo.dev/tag/v0.
|
|
196
|
+
@core(feature: "https://specs.apollo.dev/tag/v0.2")
|
|
197
197
|
@core(feature: "https://specs.apollo.dev/unsupported-feature/v0.1") {
|
|
198
198
|
query: Query
|
|
199
199
|
}
|
|
@@ -221,7 +221,7 @@ describe('core v0.2', () => {
|
|
|
221
221
|
|
|
222
222
|
directive @tag(
|
|
223
223
|
name: String!
|
|
224
|
-
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
224
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
225
225
|
|
|
226
226
|
enum CacheControlScope {
|
|
227
227
|
PRIVATE
|
|
@@ -293,7 +293,7 @@ describe('core v0.2', () => {
|
|
|
293
293
|
|
|
294
294
|
directive @tag(
|
|
295
295
|
name: String!
|
|
296
|
-
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
296
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
297
297
|
|
|
298
298
|
enum CacheControlScope {
|
|
299
299
|
PRIVATE
|
|
@@ -369,7 +369,7 @@ describe('core v0.2', () => {
|
|
|
369
369
|
|
|
370
370
|
directive @tag(
|
|
371
371
|
name: String!
|
|
372
|
-
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION
|
|
372
|
+
) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION
|
|
373
373
|
|
|
374
374
|
enum CacheControlScope {
|
|
375
375
|
PRIVATE
|
package/src/executeQueryPlan.ts
CHANGED
|
@@ -298,6 +298,7 @@ async function executeFetch<TContext>(
|
|
|
298
298
|
context,
|
|
299
299
|
fetch.operation,
|
|
300
300
|
variables,
|
|
301
|
+
fetch.operationName
|
|
301
302
|
);
|
|
302
303
|
|
|
303
304
|
for (const entity of entities) {
|
|
@@ -333,6 +334,7 @@ async function executeFetch<TContext>(
|
|
|
333
334
|
context,
|
|
334
335
|
fetch.operation,
|
|
335
336
|
{...variables, representations},
|
|
337
|
+
fetch.operationName
|
|
336
338
|
);
|
|
337
339
|
|
|
338
340
|
if (!dataReceivedFromService) {
|
|
@@ -374,6 +376,7 @@ async function executeFetch<TContext>(
|
|
|
374
376
|
context: ExecutionContext<TContext>,
|
|
375
377
|
source: string,
|
|
376
378
|
variables: Record<string, any>,
|
|
379
|
+
operationName: string | undefined
|
|
377
380
|
): Promise<ResultMap | void | null> {
|
|
378
381
|
// We declare this as 'any' because it is missing url and method, which
|
|
379
382
|
// GraphQLRequest.http is supposed to have if it exists.
|
|
@@ -402,6 +405,7 @@ async function executeFetch<TContext>(
|
|
|
402
405
|
request: {
|
|
403
406
|
query: source,
|
|
404
407
|
variables,
|
|
408
|
+
operationName,
|
|
405
409
|
http,
|
|
406
410
|
},
|
|
407
411
|
incomingRequestContext: context.requestContext,
|
package/src/index.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { deprecate } from 'util';
|
|
|
2
2
|
import { GraphQLService, Unsubscriber } from 'apollo-server-core';
|
|
3
3
|
import {
|
|
4
4
|
GraphQLExecutionResult,
|
|
5
|
-
Logger,
|
|
6
5
|
GraphQLRequestContextExecutionDidStart,
|
|
7
6
|
} from 'apollo-server-types';
|
|
7
|
+
import type { Logger } from '@apollo/utils.logger';
|
|
8
8
|
import { InMemoryLRUCache } from 'apollo-server-caching';
|
|
9
9
|
import {
|
|
10
10
|
isObjectType,
|
|
@@ -200,8 +200,12 @@ export class ApolloGateway implements GraphQLService {
|
|
|
200
200
|
this.experimental_didUpdateSupergraph =
|
|
201
201
|
config?.experimental_didUpdateSupergraph;
|
|
202
202
|
|
|
203
|
-
this.
|
|
204
|
-
|
|
203
|
+
if (isManagedConfig(this.config)) {
|
|
204
|
+
this.pollIntervalInMs =
|
|
205
|
+
this.config.fallbackPollIntervalInMs ?? this.config.pollIntervalInMs;
|
|
206
|
+
} else if (isServiceListConfig(this.config)) {
|
|
207
|
+
this.pollIntervalInMs = this.config?.pollIntervalInMs;
|
|
208
|
+
}
|
|
205
209
|
|
|
206
210
|
this.issueConfigurationWarningsIfApplicable();
|
|
207
211
|
|
|
@@ -252,7 +256,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
252
256
|
'Polling Apollo services at a frequency of less than once per 10 ' +
|
|
253
257
|
'seconds (10000) is disallowed. Instead, the minimum allowed ' +
|
|
254
258
|
'pollInterval of 10000 will be used. Please reconfigure your ' +
|
|
255
|
-
'`
|
|
259
|
+
'`fallbackPollIntervalInMs` accordingly. If this is problematic for ' +
|
|
256
260
|
'your team, please contact support.',
|
|
257
261
|
);
|
|
258
262
|
}
|
|
@@ -286,9 +290,11 @@ export class ApolloGateway implements GraphQLService {
|
|
|
286
290
|
);
|
|
287
291
|
}
|
|
288
292
|
|
|
289
|
-
if ('
|
|
293
|
+
if (isManagedConfig(this.config) && 'pollIntervalInMs' in this.config) {
|
|
290
294
|
this.logger.warn(
|
|
291
|
-
'The `
|
|
295
|
+
'The `pollIntervalInMs` option is deprecated and will be removed in a future version of `@apollo/gateway`. ' +
|
|
296
|
+
'Please migrate to the equivalent `fallbackPollIntervalInMs` configuration option. ' +
|
|
297
|
+
'The poll interval is now defined by Uplink, this option will only be used if it is greater than the value defined by Uplink or as a fallback.',
|
|
292
298
|
);
|
|
293
299
|
}
|
|
294
300
|
}
|
|
@@ -406,7 +412,7 @@ export class ApolloGateway implements GraphQLService {
|
|
|
406
412
|
subgraphHealthCheck: this.config.serviceHealthCheck,
|
|
407
413
|
fetcher: this.fetcher,
|
|
408
414
|
logger: this.logger,
|
|
409
|
-
|
|
415
|
+
fallbackPollIntervalInMs: this.pollIntervalInMs ?? 10000,
|
|
410
416
|
}),
|
|
411
417
|
);
|
|
412
418
|
}
|
|
@@ -9,7 +9,7 @@ import { IntrospectAndCompose } from '..';
|
|
|
9
9
|
import { mockAllServicesSdlQuerySuccess } from '../../../__tests__/integration/nockMocks';
|
|
10
10
|
import { getTestingSupergraphSdl, wait } from '../../../__tests__/execution-utils';
|
|
11
11
|
import resolvable from '@josephg/resolvable';
|
|
12
|
-
import { Logger } from 'apollo
|
|
12
|
+
import type { Logger } from '@apollo/utils.logger';
|
|
13
13
|
|
|
14
14
|
describe('IntrospectAndCompose', () => {
|
|
15
15
|
beforeEach(nockBeforeEach);
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* configuration options of the gateway and will be removed in a future release
|
|
5
5
|
* along with those options.
|
|
6
6
|
*/
|
|
7
|
-
import { Logger } from 'apollo
|
|
7
|
+
import type { Logger } from '@apollo/utils.logger';
|
|
8
8
|
import resolvable from '@josephg/resolvable';
|
|
9
9
|
import {
|
|
10
10
|
SupergraphManager,
|
|
@@ -65,6 +65,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
65
65
|
compositionId: "originalId-1234",
|
|
66
66
|
maxRetries: 1,
|
|
67
67
|
roundRobinSeed: 0,
|
|
68
|
+
earliestFetchTime: null,
|
|
68
69
|
});
|
|
69
70
|
|
|
70
71
|
expect(result).toMatchObject({
|
|
@@ -88,6 +89,7 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
88
89
|
compositionId: "originalId-1234",
|
|
89
90
|
maxRetries: 1,
|
|
90
91
|
roundRobinSeed: 0,
|
|
92
|
+
earliestFetchTime: null,
|
|
91
93
|
}),
|
|
92
94
|
).rejects.toThrowError(
|
|
93
95
|
new UplinkFetcherError(
|
|
@@ -388,10 +390,49 @@ describe("loadSupergraphSdlFromUplinks", () => {
|
|
|
388
390
|
compositionId: "id-1234",
|
|
389
391
|
maxRetries: 5,
|
|
390
392
|
roundRobinSeed: 0,
|
|
393
|
+
earliestFetchTime: null,
|
|
391
394
|
});
|
|
392
395
|
|
|
393
396
|
expect(result).toBeNull();
|
|
394
397
|
expect(fetcher).toHaveBeenCalledTimes(1);
|
|
395
398
|
});
|
|
399
|
+
|
|
400
|
+
it("Waits the correct time before retrying", async () => {
|
|
401
|
+
const timeoutSpy = jest.spyOn(global, 'setTimeout');
|
|
402
|
+
|
|
403
|
+
mockSupergraphSdlRequest('originalId-1234', mockCloudConfigUrl1).reply(500);
|
|
404
|
+
mockSupergraphSdlRequestIfAfter('originalId-1234', mockCloudConfigUrl2).reply(
|
|
405
|
+
200,
|
|
406
|
+
JSON.stringify({
|
|
407
|
+
data: {
|
|
408
|
+
routerConfig: {
|
|
409
|
+
__typename: 'RouterConfigResult',
|
|
410
|
+
id: 'originalId-1234',
|
|
411
|
+
supergraphSdl: getTestingSupergraphSdl()
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
}),
|
|
415
|
+
);
|
|
416
|
+
const fetcher = getDefaultFetcher();
|
|
417
|
+
|
|
418
|
+
await loadSupergraphSdlFromUplinks({
|
|
419
|
+
graphRef,
|
|
420
|
+
apiKey,
|
|
421
|
+
endpoints: [mockCloudConfigUrl1, mockCloudConfigUrl2],
|
|
422
|
+
errorReportingEndpoint: undefined,
|
|
423
|
+
fetcher: fetcher,
|
|
424
|
+
compositionId: "originalId-1234",
|
|
425
|
+
maxRetries: 1,
|
|
426
|
+
roundRobinSeed: 0,
|
|
427
|
+
earliestFetchTime: new Date(Date.now() + 1000),
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// test if setTimeout was called with a value in range to deal with time jitter
|
|
431
|
+
const setTimeoutCall = timeoutSpy.mock.calls[1][1];
|
|
432
|
+
expect(setTimeoutCall).toBeLessThanOrEqual(1000);
|
|
433
|
+
expect(setTimeoutCall).toBeGreaterThanOrEqual(900);
|
|
434
|
+
|
|
435
|
+
timeoutSpy.mockRestore();
|
|
436
|
+
});
|
|
396
437
|
});
|
|
397
438
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { fetch } from 'apollo-server-env';
|
|
2
|
-
import { Logger } from 'apollo
|
|
2
|
+
import type { Logger } from '@apollo/utils.logger';
|
|
3
3
|
import resolvable from '@josephg/resolvable';
|
|
4
4
|
import { SupergraphManager, SupergraphSdlHookOptions } from '../../config';
|
|
5
5
|
import { SubgraphHealthCheckFunction, SupergraphSdlUpdateFunction } from '../..';
|
|
6
6
|
import { loadSupergraphSdlFromUplinks } from './loadSupergraphSdlFromStorage';
|
|
7
7
|
|
|
8
8
|
export interface UplinkFetcherOptions {
|
|
9
|
-
|
|
9
|
+
fallbackPollIntervalInMs: number;
|
|
10
10
|
subgraphHealthCheck?: boolean;
|
|
11
11
|
graphRef: string;
|
|
12
12
|
apiKey: string;
|
|
@@ -31,6 +31,8 @@ export class UplinkFetcher implements SupergraphManager {
|
|
|
31
31
|
process.env.APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT ?? undefined;
|
|
32
32
|
private compositionId?: string;
|
|
33
33
|
private fetchCount: number = 0;
|
|
34
|
+
private minDelayMs: number | null = null;
|
|
35
|
+
private earliestFetchTime: Date | null = null;
|
|
34
36
|
|
|
35
37
|
constructor(options: UplinkFetcherOptions) {
|
|
36
38
|
this.config = options;
|
|
@@ -46,7 +48,12 @@ export class UplinkFetcher implements SupergraphManager {
|
|
|
46
48
|
|
|
47
49
|
let initialSupergraphSdl: string | null = null;
|
|
48
50
|
try {
|
|
49
|
-
|
|
51
|
+
const result = await this.updateSupergraphSdl();
|
|
52
|
+
initialSupergraphSdl = result?.supergraphSdl || null;
|
|
53
|
+
if (result?.minDelaySeconds) {
|
|
54
|
+
this.minDelayMs = 1000 * result?.minDelaySeconds;
|
|
55
|
+
this.earliestFetchTime = new Date(Date.now() + this.minDelayMs);
|
|
56
|
+
}
|
|
50
57
|
} catch (e) {
|
|
51
58
|
this.logUpdateFailure(e);
|
|
52
59
|
throw e;
|
|
@@ -83,6 +90,7 @@ export class UplinkFetcher implements SupergraphManager {
|
|
|
83
90
|
compositionId: this.compositionId ?? null,
|
|
84
91
|
maxRetries: this.config.maxRetries,
|
|
85
92
|
roundRobinSeed: this.fetchCount++,
|
|
93
|
+
earliestFetchTime: this.earliestFetchTime,
|
|
86
94
|
});
|
|
87
95
|
|
|
88
96
|
if (!result) {
|
|
@@ -91,7 +99,8 @@ export class UplinkFetcher implements SupergraphManager {
|
|
|
91
99
|
this.compositionId = result.id;
|
|
92
100
|
// the healthCheck fn is only assigned if it's enabled in the config
|
|
93
101
|
await this.healthCheck?.(result.supergraphSdl);
|
|
94
|
-
|
|
102
|
+
const { supergraphSdl, minDelaySeconds } = result;
|
|
103
|
+
return { supergraphSdl, minDelaySeconds };
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
|
|
@@ -101,24 +110,34 @@ export class UplinkFetcher implements SupergraphManager {
|
|
|
101
110
|
}
|
|
102
111
|
|
|
103
112
|
private poll() {
|
|
104
|
-
this.timerRef = setTimeout(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
this.timerRef = setTimeout(
|
|
114
|
+
async () => {
|
|
115
|
+
if (this.state.phase === 'polling') {
|
|
116
|
+
const pollingPromise = resolvable();
|
|
117
|
+
|
|
118
|
+
this.state.pollingPromise = pollingPromise;
|
|
119
|
+
try {
|
|
120
|
+
const result = await this.updateSupergraphSdl();
|
|
121
|
+
const maybeNewSupergraphSdl = result?.supergraphSdl || null;
|
|
122
|
+
if (result?.minDelaySeconds) {
|
|
123
|
+
this.minDelayMs = 1000 * result?.minDelaySeconds;
|
|
124
|
+
this.earliestFetchTime = new Date(Date.now() + this.minDelayMs);
|
|
125
|
+
}
|
|
126
|
+
if (maybeNewSupergraphSdl) {
|
|
127
|
+
this.update?.(maybeNewSupergraphSdl);
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
this.logUpdateFailure(e);
|
|
113
131
|
}
|
|
114
|
-
|
|
115
|
-
this.logUpdateFailure(e);
|
|
132
|
+
pollingPromise.resolve();
|
|
116
133
|
}
|
|
117
|
-
pollingPromise.resolve();
|
|
118
|
-
}
|
|
119
134
|
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
this.poll();
|
|
136
|
+
},
|
|
137
|
+
this.minDelayMs
|
|
138
|
+
? Math.max(this.minDelayMs, this.config.fallbackPollIntervalInMs)
|
|
139
|
+
: this.config.fallbackPollIntervalInMs,
|
|
140
|
+
);
|
|
122
141
|
}
|
|
123
142
|
|
|
124
143
|
private logUpdateFailure(e: any) {
|
|
@@ -13,6 +13,7 @@ export const SUPERGRAPH_SDL_QUERY = /* GraphQL */`#graphql
|
|
|
13
13
|
... on RouterConfigResult {
|
|
14
14
|
id
|
|
15
15
|
supergraphSdl: supergraphSDL
|
|
16
|
+
minDelaySeconds
|
|
16
17
|
}
|
|
17
18
|
... on FetchError {
|
|
18
19
|
code
|
|
@@ -56,6 +57,7 @@ export async function loadSupergraphSdlFromUplinks({
|
|
|
56
57
|
compositionId,
|
|
57
58
|
maxRetries,
|
|
58
59
|
roundRobinSeed,
|
|
60
|
+
earliestFetchTime,
|
|
59
61
|
}: {
|
|
60
62
|
graphRef: string;
|
|
61
63
|
apiKey: string;
|
|
@@ -65,6 +67,7 @@ export async function loadSupergraphSdlFromUplinks({
|
|
|
65
67
|
compositionId: string | null;
|
|
66
68
|
maxRetries: number,
|
|
67
69
|
roundRobinSeed: number,
|
|
70
|
+
earliestFetchTime: Date | null
|
|
68
71
|
}) : Promise<SupergraphSdlUpdate | null> {
|
|
69
72
|
// This Promise resolves with either an updated supergraph or null if no change.
|
|
70
73
|
// This Promise can reject in the case that none of the retries are successful,
|
|
@@ -81,6 +84,10 @@ export async function loadSupergraphSdlFromUplinks({
|
|
|
81
84
|
}),
|
|
82
85
|
{
|
|
83
86
|
retries: maxRetries,
|
|
87
|
+
onRetry: async () => {
|
|
88
|
+
const delayMS = earliestFetchTime ? earliestFetchTime.getTime() - Date.now(): 0;
|
|
89
|
+
if (delayMS > 0) await new Promise(resolve => setTimeout(resolve, delayMS));
|
|
90
|
+
}
|
|
84
91
|
},
|
|
85
92
|
);
|
|
86
93
|
|
|
@@ -176,9 +183,10 @@ export async function loadSupergraphSdlFromStorage({
|
|
|
176
183
|
const {
|
|
177
184
|
id,
|
|
178
185
|
supergraphSdl,
|
|
186
|
+
minDelaySeconds,
|
|
179
187
|
// messages,
|
|
180
188
|
} = routerConfig;
|
|
181
|
-
return { id, supergraphSdl: supergraphSdl
|
|
189
|
+
return { id, supergraphSdl: supergraphSdl!, minDelaySeconds };
|
|
182
190
|
} else if (routerConfig.__typename === 'FetchError') {
|
|
183
191
|
// FetchError case
|
|
184
192
|
const { code, message } = routerConfig;
|