|
1 | 1 | import { deprecate } from 'util';
|
2 | 2 | import { createHash } from '@apollo/utils.createhash';
|
3 | 3 | import type { Logger } from '@apollo/utils.logger';
|
4 |
| -import { QueryPlanCache } from '@apollo/query-planner' |
| 4 | +import { QueryPlanCache } from '@apollo/query-planner'; |
5 | 5 | import { InMemoryLRUCache } from '@apollo/utils.keyvaluecache';
|
6 | 6 | import {
|
7 | 7 | GraphQLSchema,
|
@@ -47,7 +47,7 @@ import {
|
47 | 47 | requestContextSpanAttributes,
|
48 | 48 | operationContextSpanAttributes,
|
49 | 49 | recordExceptions,
|
50 |
| - OpenTelemetryAttributeNames |
| 50 | + OpenTelemetryAttributeNames, |
51 | 51 | } from './utilities/opentelemetry';
|
52 | 52 | import { addExtensions } from './schema-helper/addExtensions';
|
53 | 53 | import {
|
@@ -141,6 +141,12 @@ export class ApolloGateway implements GatewayInterface {
|
141 | 141 | coreSupergraphSdl: string;
|
142 | 142 | }) => void
|
143 | 143 | >();
|
| 144 | + private onSchemaWillBeUsedListeners = new Set< |
| 145 | + (schemaContext: { |
| 146 | + apiSchema: GraphQLSchema; |
| 147 | + coreSupergraphSdl: string; |
| 148 | + }) => void |
| 149 | + >(); |
144 | 150 | private warnedStates: WarnedStates = Object.create(null);
|
145 | 151 | private queryPlanner?: QueryPlanner;
|
146 | 152 | private supergraphSdl?: string;
|
@@ -198,8 +204,8 @@ export class ApolloGateway implements GatewayInterface {
|
198 | 204 | }
|
199 | 205 |
|
200 | 206 | private initQueryPlanStore(approximateQueryPlanStoreMiB?: number) {
|
201 |
| - if(this.config.queryPlannerConfig?.cache){ |
202 |
| - return this.config.queryPlannerConfig?.cache |
| 207 | + if (this.config.queryPlannerConfig?.cache) { |
| 208 | + return this.config.queryPlannerConfig?.cache; |
203 | 209 | }
|
204 | 210 | // Create ~about~ a 30MiB InMemoryLRUCache (or 50MiB if the full operation ASTs are
|
205 | 211 | // enabled in query plans as this requires plans to use more memory). This is
|
@@ -569,6 +575,23 @@ export class ApolloGateway implements GatewayInterface {
|
569 | 575 | legacyDontNotifyOnSchemaChangeListeners: boolean = false,
|
570 | 576 | ): void {
|
571 | 577 | this.queryPlanStore.clear();
|
| 578 | + |
| 579 | + // Notify before use of new schema |
| 580 | + this.onSchemaWillBeUsedListeners.forEach((listener) => { |
| 581 | + try { |
| 582 | + listener({ |
| 583 | + apiSchema: this.schema!, |
| 584 | + coreSupergraphSdl: supergraphSdl, |
| 585 | + }); |
| 586 | + } catch (e) { |
| 587 | + this.logger.error( |
| 588 | + "An error was thrown from an 'onSchemaWillBeUsed' listener. " + |
| 589 | + 'The schema will still update: ' + |
| 590 | + ((e && e.message) || e), |
| 591 | + ); |
| 592 | + } |
| 593 | + }); |
| 594 | + |
572 | 595 | this.apiSchema = supergraph.apiSchema();
|
573 | 596 | this.schema = addExtensions(this.apiSchema.toGraphQLJSSchema());
|
574 | 597 |
|
@@ -681,6 +704,19 @@ export class ApolloGateway implements GatewayInterface {
|
681 | 704 | };
|
682 | 705 | }
|
683 | 706 |
|
| 707 | + public onSchemaWillBeUsed( |
| 708 | + callback: (schemaContext: { |
| 709 | + apiSchema: GraphQLSchema; |
| 710 | + coreSupergraphSdl: string; |
| 711 | + }) => void, |
| 712 | + ): GatewayUnsubscriber { |
| 713 | + this.onSchemaWillBeUsedListeners.add(callback); |
| 714 | + |
| 715 | + return () => { |
| 716 | + this.onSchemaWillBeUsedListeners.delete(callback); |
| 717 | + }; |
| 718 | + } |
| 719 | + |
684 | 720 | private getOrCreateDataSource(
|
685 | 721 | serviceDef: ServiceEndpointDefinition,
|
686 | 722 | ): GraphQLDataSource {
|
@@ -850,7 +886,7 @@ export class ApolloGateway implements GatewayInterface {
|
850 | 886 | operationContext,
|
851 | 887 | this.supergraphSchema!,
|
852 | 888 | this.apiSchema!,
|
853 |
| - this.config.telemetry |
| 889 | + this.config.telemetry, |
854 | 890 | );
|
855 | 891 |
|
856 | 892 | const shouldShowQueryPlan =
|
|
0 commit comments