@apollo/gateway
Version:
620 lines • 32.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UplinkFetcherError = exports.UplinkSupergraphManager = exports.LocalCompose = exports.IntrospectAndCompose = exports.buildOperationContext = exports.executeQueryPlan = exports.ApolloGateway = exports.SERVICE_DEFINITION_QUERY = exports.HEALTH_CHECK_QUERY = void 0;
const util_1 = require("util");
const utils_createhash_1 = require("@apollo/utils.createhash");
const utils_keyvaluecache_1 = require("@apollo/utils.keyvaluecache");
const operationContext_1 = require("./operationContext");
Object.defineProperty(exports, "buildOperationContext", { enumerable: true, get: function () { return operationContext_1.buildOperationContext; } });
const executeQueryPlan_1 = require("./executeQueryPlan");
Object.defineProperty(exports, "executeQueryPlan", { enumerable: true, get: function () { return executeQueryPlan_1.executeQueryPlan; } });
const types_1 = require("./datasources/types");
const RemoteGraphQLDataSource_1 = require("./datasources/RemoteGraphQLDataSource");
const values_1 = require("graphql/execution/values");
const query_planner_1 = require("@apollo/query-planner");
const config_1 = require("./config");
const api_1 = require("@opentelemetry/api");
const opentelemetry_1 = require("./utilities/opentelemetry");
const addExtensions_1 = require("./schema-helper/addExtensions");
const supergraphManagers_1 = require("./supergraphManagers");
Object.defineProperty(exports, "IntrospectAndCompose", { enumerable: true, get: function () { return supergraphManagers_1.IntrospectAndCompose; } });
Object.defineProperty(exports, "UplinkSupergraphManager", { enumerable: true, get: function () { return supergraphManagers_1.UplinkSupergraphManager; } });
Object.defineProperty(exports, "LocalCompose", { enumerable: true, get: function () { return supergraphManagers_1.LocalCompose; } });
const federation_internals_1 = require("@apollo/federation-internals");
const logger_1 = require("./logger");
exports.HEALTH_CHECK_QUERY = 'query __ApolloServiceHealthCheck__ { __typename }';
exports.SERVICE_DEFINITION_QUERY = 'query __ApolloGetServiceDefinition__ { _service { sdl } }';
class ApolloGateway {
constructor(config) {
var _a, _b, _c;
this.serviceMap = Object.create(null);
this.onSchemaChangeListeners = new Set();
this.onSchemaLoadOrUpdateListeners = new Set();
this.warnedStates = Object.create(null);
this.toDispose = [];
this.executor = async (requestContext) => {
return opentelemetry_1.tracer.startActiveSpan(opentelemetry_1.OpenTelemetrySpanNames.REQUEST, { attributes: (0, opentelemetry_1.requestContextSpanAttributes)(requestContext, this.config.telemetry) }, async (span) => {
try {
const { request, document, queryHash } = requestContext;
const queryPlanStoreKey = request.operationName ?
(0, utils_createhash_1.createHash)('sha256').update(queryHash).update(request.operationName).digest('hex')
: queryHash;
const operationContext = (0, operationContext_1.buildOperationContext)({
schema: this.schema,
operationDocument: document,
operationName: request.operationName,
});
span.setAttributes((0, opentelemetry_1.operationContextSpanAttributes)(operationContext));
const validationErrors = this.validateIncomingRequest(requestContext, operationContext);
if (validationErrors.length > 0) {
(0, opentelemetry_1.recordExceptions)(span, validationErrors, this.config.telemetry);
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
return { errors: validationErrors };
}
let queryPlan = await this.queryPlanStore.get(queryPlanStoreKey);
if (!queryPlan) {
queryPlan = opentelemetry_1.tracer.startActiveSpan(opentelemetry_1.OpenTelemetrySpanNames.PLAN, requestContext.operationName
? {
attributes: {
[opentelemetry_1.OpenTelemetryAttributeNames.GRAPHQL_OPERATION_NAME]: requestContext.operationName,
},
}
: {}, (span) => {
try {
const operation = (0, federation_internals_1.operationFromDocument)(this.apiSchema, document, { operationName: request.operationName });
return this.queryPlanner.buildQueryPlan(operation, {
recursiveSelectionsLimitDisabled: this.recursiveSelectionsLimitDisabled,
nonLocalSelectionsLimitDisabled: this.nonLocalSelectionsLimitDisabled,
});
}
catch (err) {
(0, opentelemetry_1.recordExceptions)(span, [err], this.config.telemetry);
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
throw err;
}
finally {
span.end();
}
});
try {
await this.queryPlanStore.set(queryPlanStoreKey, queryPlan);
}
catch (err) {
this.logger.warn('Could not store queryPlan' + ((err && err.message) || err));
}
}
const serviceMap = Object.entries(this.serviceMap).reduce((serviceDataSources, [serviceName, { dataSource }]) => {
serviceDataSources[serviceName] = dataSource;
return serviceDataSources;
}, Object.create(null));
if (this.experimental_didResolveQueryPlan) {
this.experimental_didResolveQueryPlan({
queryPlan,
serviceMap,
requestContext,
operationContext,
});
}
const response = await (0, executeQueryPlan_1.executeQueryPlan)(queryPlan, serviceMap, requestContext, operationContext, this.supergraphSchema, this.apiSchema, this.config.telemetry);
const shouldShowQueryPlan = this.config.__exposeQueryPlanExperimental &&
request.http &&
request.http.headers &&
request.http.headers.get('Apollo-Query-Plan-Experimental');
const serializedQueryPlan = queryPlan.node && (this.config.debug || shouldShowQueryPlan)
?
(0, query_planner_1.prettyFormatQueryPlan)(queryPlan)
: null;
if (this.config.debug && serializedQueryPlan) {
this.logger.debug(serializedQueryPlan);
}
if (shouldShowQueryPlan) {
const queryPlanFormat = request.http &&
request.http.headers &&
request.http.headers.has('Apollo-Query-Plan-Experimental-Format')
? request.http.headers.get('Apollo-Query-Plan-Experimental-Format')
: 'prettified';
response.extensions = {
__queryPlanExperimental: queryPlanFormat === 'prettified'
? serializedQueryPlan || true
: queryPlanFormat === 'internal'
? queryPlan
: true
};
}
if (response.errors) {
(0, opentelemetry_1.recordExceptions)(span, response.errors, this.config.telemetry);
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
}
return response;
}
catch (err) {
(0, opentelemetry_1.recordExceptions)(span, [err], this.config.telemetry);
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
throw err;
}
finally {
span.end();
}
});
};
this.config = {
__exposeQueryPlanExperimental: process.env.NODE_ENV !== 'production',
...config,
};
this.logger = (_a = this.config.logger) !== null && _a !== void 0 ? _a : (0, logger_1.getDefaultLogger)(this.config.debug);
this.queryPlanStore = this.initQueryPlanStore(config === null || config === void 0 ? void 0 : config.experimental_approximateQueryPlanStoreMiB);
this.experimental_didResolveQueryPlan =
config === null || config === void 0 ? void 0 : config.experimental_didResolveQueryPlan;
this.experimental_didUpdateSupergraph =
config === null || config === void 0 ? void 0 : config.experimental_didUpdateSupergraph;
this.recursiveSelectionsLimitDisabled =
process.env.APOLLO_DISABLE_SECURITY_RECURSIVE_SELECTIONS_CHECK === 'true';
this.nonLocalSelectionsLimitDisabled =
process.env.APOLLO_DISABLE_SECURITY_NON_LOCAL_SELECTIONS_CHECK === 'true';
if ((0, config_1.isManagedConfig)(this.config)) {
this.pollIntervalInMs =
(_b = this.config.fallbackPollIntervalInMs) !== null && _b !== void 0 ? _b : this.config.pollIntervalInMs;
}
else if ((0, config_1.isServiceListConfig)(this.config)) {
this.pollIntervalInMs = (_c = this.config) === null || _c === void 0 ? void 0 : _c.pollIntervalInMs;
}
this.validateConfigAndEmitWarnings();
this.logger.debug('Gateway successfully initialized (but not yet loaded)');
this.state = { phase: 'initialized' };
}
get supergraphManager() {
return this._supergraphManager;
}
initQueryPlanStore(approximateQueryPlanStoreMiB) {
var _a, _b, _c;
if ((_a = this.config.queryPlannerConfig) === null || _a === void 0 ? void 0 : _a.cache) {
return (_b = this.config.queryPlannerConfig) === null || _b === void 0 ? void 0 : _b.cache;
}
const defaultSize = ((_c = this.config.queryPlannerConfig) === null || _c === void 0 ? void 0 : _c.exposeDocumentNodeInFetchNode) ? 50 : 30;
return new utils_keyvaluecache_1.InMemoryLRUCache({
maxSize: Math.pow(2, 20) * (approximateQueryPlanStoreMiB || defaultSize),
sizeCalculation: approximateObjectSize,
});
}
validateConfigAndEmitWarnings() {
var _a;
(0, federation_internals_1.assert)(!((_a = this.config.queryPlannerConfig) === null || _a === void 0 ? void 0 : _a.typeConditionedFetching), "Type conditions are not supported in the gateway");
if (this.pollIntervalInMs && (0, config_1.isServiceListConfig)(this.config)) {
this.logger.warn('Polling running services is dangerous and not recommended in production. ' +
'Polling should only be used against a registry. ' +
'If you are polling running services, use with caution.');
}
if ((0, config_1.isManuallyManagedConfig)(this.config) &&
'experimental_updateSupergraphSdl' in this.config &&
'experimental_updateServiceDefinitions' in this.config) {
this.logger.warn('Gateway found two manual update configurations when only one should be ' +
'provided. Gateway will default to using the provided `experimental_updateSupergraphSdl` ' +
'function when both `experimental_updateSupergraphSdl` and experimental_updateServiceDefinitions` ' +
'are provided.');
}
if ('schemaConfigDeliveryEndpoint' in this.config) {
this.logger.warn('The `schemaConfigDeliveryEndpoint` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to the equivalent (array form) `uplinkEndpoints` configuration option.');
}
if ((0, config_1.isManagedConfig)(this.config) && 'pollIntervalInMs' in this.config) {
this.logger.warn('The `pollIntervalInMs` option is deprecated and will be removed in a future version of `@apollo/gateway`. ' +
'Please migrate to the equivalent `fallbackPollIntervalInMs` configuration option. ' +
'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.');
}
}
async load(options) {
var _a, _b, _c;
this.logger.debug('Loading gateway...');
if (this.state.phase !== 'initialized') {
throw Error(`ApolloGateway.load called in surprising state ${this.state.phase}`);
}
if (options === null || options === void 0 ? void 0 : options.apollo) {
const { key, keyHash, graphRef, graphId, graphVariant } = options.apollo;
this.apolloConfig = {
key,
keyHash,
graphRef: graphRef !== null && graphRef !== void 0 ? graphRef : (graphId ? `${graphId}@${graphVariant !== null && graphVariant !== void 0 ? graphVariant : 'current'}` : undefined),
};
}
else if (options === null || options === void 0 ? void 0 : options.engine) {
const { apiKeyHash, graphId, graphVariant } = options.engine;
this.apolloConfig = {
keyHash: apiKeyHash,
graphRef: graphId
? `${graphId}@${graphVariant !== null && graphVariant !== void 0 ? graphVariant : 'current'}`
: undefined,
};
}
this.maybeWarnOnConflictingConfig();
if ((0, config_1.isStaticSupergraphSdlConfig)(this.config)) {
const supergraphSdl = this.config.supergraphSdl;
await this.initializeSupergraphManager({
initialize: async () => {
return {
supergraphSdl,
};
},
});
}
else if ((0, config_1.isLocalConfig)(this.config)) {
await this.initializeSupergraphManager(new supergraphManagers_1.LocalCompose({
localServiceList: this.config.localServiceList,
logger: this.logger,
}));
}
else if ((0, config_1.isManuallyManagedSupergraphSdlGatewayConfig)(this.config)) {
const supergraphManager = typeof this.config.supergraphSdl === 'object'
? this.config.supergraphSdl
: { initialize: this.config.supergraphSdl };
await this.initializeSupergraphManager(supergraphManager);
}
else if ('experimental_updateServiceDefinitions' in this.config ||
'experimental_updateSupergraphSdl' in this.config) {
const updateServiceDefinitions = 'experimental_updateServiceDefinitions' in this.config
? this.config.experimental_updateServiceDefinitions
: this.config.experimental_updateSupergraphSdl;
await this.initializeSupergraphManager(new supergraphManagers_1.LegacyFetcher({
logger: this.logger,
gatewayConfig: this.config,
updateServiceDefinitions,
pollIntervalInMs: this.pollIntervalInMs,
subgraphHealthCheck: this.config.serviceHealthCheck,
}));
}
else if ((0, config_1.isServiceListConfig)(this.config)) {
this.logger.warn('The `serviceList` option is deprecated and will be removed in a future version of `@apollo/gateway`. Please migrate to its replacement `IntrospectAndCompose`. More information on `IntrospectAndCompose` can be found in the documentation.');
await this.initializeSupergraphManager(new supergraphManagers_1.IntrospectAndCompose({
subgraphs: this.config.serviceList,
pollIntervalInMs: this.pollIntervalInMs,
logger: this.logger,
subgraphHealthCheck: this.config.serviceHealthCheck,
introspectionHeaders: this.config.introspectionHeaders,
}));
}
else {
const canUseManagedConfig = ((_a = this.apolloConfig) === null || _a === void 0 ? void 0 : _a.graphRef) && ((_b = this.apolloConfig) === null || _b === void 0 ? void 0 : _b.keyHash);
if (!canUseManagedConfig) {
throw new Error('When a manual configuration is not provided, gateway requires an Apollo ' +
'configuration. See https://www.apollographql.com/docs/apollo-server/federation/managed-federation/ ' +
'for more information. Manual configuration options include: ' +
'`serviceList`, `supergraphSdl`, and `experimental_updateServiceDefinitions`.');
}
const schemaDeliveryEndpoints = this.config
.schemaConfigDeliveryEndpoint
? [this.config.schemaConfigDeliveryEndpoint]
: undefined;
await this.initializeSupergraphManager(new supergraphManagers_1.UplinkSupergraphManager({
graphRef: this.apolloConfig.graphRef,
apiKey: this.apolloConfig.key,
shouldRunSubgraphHealthcheck: this.config.serviceHealthCheck,
uplinkEndpoints: (_c = this.config.uplinkEndpoints) !== null && _c !== void 0 ? _c : schemaDeliveryEndpoints,
maxRetries: this.config.uplinkMaxRetries,
fetcher: this.config.fetcher,
logger: this.logger,
fallbackPollIntervalInMs: this.pollIntervalInMs,
}));
}
const mode = (0, config_1.isManagedConfig)(this.config) ? 'managed' : 'unmanaged';
this.logger.info(`Gateway successfully loaded schema.\n\t* Mode: ${mode}${this.apolloConfig && this.apolloConfig.graphRef
? `\n\t* Service: ${this.apolloConfig.graphRef}`
: ''}`);
(0, addExtensions_1.addExtensions)(this.schema);
return {
schema: this.schema,
executor: this.executor,
};
}
getIdForSupergraphSdl(supergraphSdl) {
return (0, utils_createhash_1.createHash)('sha256').update(supergraphSdl).digest('hex');
}
async initializeSupergraphManager(supergraphManager) {
try {
const result = await supergraphManager.initialize({
update: this.externalSupergraphUpdateCallback.bind(this),
healthCheck: this.externalSubgraphHealthCheckCallback.bind(this),
getDataSource: this.externalGetDataSourceCallback.bind(this),
});
if (result === null || result === void 0 ? void 0 : result.cleanup) {
if (typeof result.cleanup === 'function') {
this.toDispose.push(result.cleanup);
}
else {
this.logger.error('Provided `supergraphSdl` function returned an invalid `cleanup` property (must be a function)');
}
}
this.externalSupergraphUpdateCallback(result.supergraphSdl);
}
catch (e) {
this.state = { phase: 'failed to load' };
await this.performCleanupAndLogErrors();
throw e;
}
this._supergraphManager = supergraphManager;
this.state = { phase: 'loaded' };
}
externalSupergraphUpdateCallback(supergraphSdl) {
switch (this.state.phase) {
case 'failed to load':
throw new Error("Can't call `update` callback after gateway failed to load.");
case 'updating schema':
throw new Error("Can't call `update` callback while supergraph update is in progress.");
case 'stopped':
throw new Error("Can't call `update` callback after gateway has been stopped.");
case 'stopping':
throw new Error("Can't call `update` callback while gateway is stopping.");
case 'loaded':
case 'initialized':
break;
default:
throw new UnreachableCaseError(this.state);
}
this.state = { phase: 'updating schema' };
try {
this.updateWithSupergraphSdl({
supergraphSdl,
id: this.getIdForSupergraphSdl(supergraphSdl),
});
}
finally {
this.state = { phase: 'loaded' };
}
}
async externalSubgraphHealthCheckCallback(supergraphSdl) {
const serviceList = this.serviceListFromSupergraphSdl(supergraphSdl);
const serviceMap = serviceList.reduce((serviceMap, serviceDef) => {
serviceMap[serviceDef.name] = {
url: serviceDef.url,
dataSource: this.createDataSource(serviceDef),
};
return serviceMap;
}, Object.create(null));
try {
await this.serviceHealthCheck(serviceMap);
}
catch (e) {
throw new Error('The gateway subgraphs health check failed. Updating to the provided ' +
'`supergraphSdl` will likely result in future request failures to ' +
'subgraphs. The following error occurred during the health check:\n' +
e.message);
}
}
externalGetDataSourceCallback({ name, url, }) {
return this.getOrCreateDataSource({ name, url });
}
updateWithSupergraphSdl(result) {
if (result.id === this.compositionId) {
this.logger.debug('No change in composition since last check.');
return;
}
const { supergraph, supergraphSdl } = this.createSchemaFromSupergraphSdl(result.supergraphSdl);
const previousSchema = this.schema;
const previousSupergraphSdl = this.supergraphSdl;
const previousCompositionId = this.compositionId;
if (previousSchema) {
this.logger.info(`Updated Supergraph SDL was found [Composition ID ${this.compositionId} => ${result.id}]`);
}
this.compositionId = result.id;
this.supergraphSdl = supergraphSdl;
this.supergraphSchema = supergraph.schema.toGraphQLJSSchema();
if (!supergraphSdl) {
this.logger.error("A valid schema couldn't be composed. Falling back to previous schema.");
}
else {
this.updateWithSchemaAndNotify(supergraph, supergraphSdl);
if (this.experimental_didUpdateSupergraph) {
this.experimental_didUpdateSupergraph({
compositionId: result.id,
supergraphSdl,
schema: this.schema,
}, previousCompositionId && previousSupergraphSdl && previousSchema
? {
compositionId: previousCompositionId,
supergraphSdl: previousSupergraphSdl,
schema: previousSchema,
}
: undefined);
}
}
}
updateWithSchemaAndNotify(supergraph, supergraphSdl, legacyDontNotifyOnSchemaChangeListeners = false) {
this.queryPlanStore.clear();
this.apiSchema = supergraph.apiSchema();
this.schema = (0, addExtensions_1.addExtensions)(this.apiSchema.toGraphQLJSSchema());
this.queryPlanner = new query_planner_1.QueryPlanner(supergraph, this.config.queryPlannerConfig);
if (!legacyDontNotifyOnSchemaChangeListeners) {
this.onSchemaChangeListeners.forEach((listener) => {
try {
listener(this.schema);
}
catch (e) {
this.logger.error("An error was thrown from an 'onSchemaChange' listener. " +
'The schema will still update: ' +
((e && e.message) || e));
}
});
}
this.onSchemaLoadOrUpdateListeners.forEach((listener) => {
try {
listener({
apiSchema: this.schema,
coreSupergraphSdl: supergraphSdl,
});
}
catch (e) {
this.logger.error("An error was thrown from an 'onSchemaLoadOrUpdate' listener. " +
'The schema will still update: ' +
((e && e.message) || e));
}
});
}
serviceHealthCheck(serviceMap = this.serviceMap) {
return Promise.all(Object.entries(serviceMap).map(([name, { dataSource }]) => dataSource
.process({
kind: types_1.GraphQLDataSourceRequestKind.HEALTH_CHECK,
request: { query: exports.HEALTH_CHECK_QUERY },
context: {},
})
.then((response) => ({ name, response }))
.catch((e) => {
throw new Error(`[${name}]: ${e.message}`);
})));
}
serviceListFromSupergraphSdl(supergraphSdl) {
return federation_internals_1.Supergraph.build(supergraphSdl).subgraphsMetadata();
}
createSchemaFromSupergraphSdl(supergraphSdl) {
var _a;
const validateSupergraph = (_a = this.config.validateSupergraph) !== null && _a !== void 0 ? _a : process.env.NODE_ENV !== 'production';
const supergraph = federation_internals_1.Supergraph.build(supergraphSdl, { validateSupergraph });
this.createServices(supergraph.subgraphsMetadata());
return {
supergraph,
supergraphSdl,
};
}
onSchemaChange(callback) {
this.onSchemaChangeListeners.add(callback);
return () => {
this.onSchemaChangeListeners.delete(callback);
};
}
onSchemaLoadOrUpdate(callback) {
this.onSchemaLoadOrUpdateListeners.add(callback);
return () => {
this.onSchemaLoadOrUpdateListeners.delete(callback);
};
}
getOrCreateDataSource(serviceDef) {
if (this.serviceMap[serviceDef.name] &&
serviceDef.url === this.serviceMap[serviceDef.name].url) {
return this.serviceMap[serviceDef.name].dataSource;
}
const dataSource = this.createDataSource(serviceDef);
this.serviceMap[serviceDef.name] = { url: serviceDef.url, dataSource };
return dataSource;
}
createDataSource(serviceDef) {
if (!serviceDef.url && !(0, config_1.isLocalConfig)(this.config)) {
this.logger.error(`Service definition for service ${serviceDef.name} is missing a url`);
}
return this.config.buildService
? this.config.buildService(serviceDef)
: new RemoteGraphQLDataSource_1.RemoteGraphQLDataSource({
url: serviceDef.url,
});
}
createServices(services) {
for (const serviceDef of services) {
this.getOrCreateDataSource(serviceDef);
}
}
maybeWarnOnConflictingConfig() {
var _a, _b;
const canUseManagedConfig = ((_a = this.apolloConfig) === null || _a === void 0 ? void 0 : _a.graphRef) && ((_b = this.apolloConfig) === null || _b === void 0 ? void 0 : _b.keyHash);
if (!(0, config_1.isManagedConfig)(this.config) &&
canUseManagedConfig &&
!this.warnedStates.remoteWithLocalConfig) {
this.warnedStates.remoteWithLocalConfig = true;
this.logger.warn('A local gateway configuration is overriding a managed federation ' +
'configuration. To use the managed ' +
'configuration, do not specify a service list or supergraphSdl locally.');
}
}
validateIncomingRequest(requestContext, operationContext) {
return opentelemetry_1.tracer.startActiveSpan(opentelemetry_1.OpenTelemetrySpanNames.VALIDATE, (span) => {
try {
const variableDefinitions = operationContext.operation
.variableDefinitions;
if (!variableDefinitions)
return [];
const { errors } = (0, values_1.getVariableValues)(operationContext.schema, variableDefinitions, requestContext.request.variables || {});
if (errors) {
(0, opentelemetry_1.recordExceptions)(span, errors, this.config.telemetry);
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
}
return errors || [];
}
catch (err) {
(0, opentelemetry_1.recordExceptions)(span, [err], this.config.telemetry);
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
throw err;
}
finally {
span.end();
}
});
}
async performCleanupAndLogErrors() {
if (this.toDispose.length === 0)
return;
await Promise.all(this.toDispose.map((p) => p().catch((e) => {
var _a;
this.logger.error('Error occured while calling user provided `cleanup` function: ' +
((_a = e.message) !== null && _a !== void 0 ? _a : e));
})));
this.toDispose = [];
}
async stop() {
switch (this.state.phase) {
case 'initialized':
case 'failed to load':
case 'stopped':
return;
case 'stopping':
await this.state.stoppingDonePromise;
if (this.state.phase !== 'stopped') {
throw Error(`Expected to be stopped when done stopping, but instead ${this.state.phase}`);
}
return;
case 'loaded':
const stoppingDonePromise = this.performCleanupAndLogErrors();
this.state = {
phase: 'stopping',
stoppingDonePromise,
};
await stoppingDonePromise;
this.state = { phase: 'stopped' };
return;
case 'updating schema': {
throw Error("`ApolloGateway.stop` shouldn't be called from inside a schema change listener");
}
default:
throw new UnreachableCaseError(this.state);
}
}
__testing() {
return {
state: this.state,
compositionId: this.compositionId,
supergraphSdl: this.supergraphSdl,
queryPlanner: this.queryPlanner,
};
}
}
exports.ApolloGateway = ApolloGateway;
ApolloGateway.prototype.onSchemaChange = (0, util_1.deprecate)(ApolloGateway.prototype.onSchemaChange, `'ApolloGateway.prototype.onSchemaChange' is deprecated. Use 'ApolloGateway.prototype.onSchemaLoadOrUpdate' instead.`);
function approximateObjectSize(obj) {
return Buffer.byteLength(JSON.stringify(obj), 'utf8');
}
class UnreachableCaseError extends Error {
constructor(val) {
super(`Unreachable case: ${val}`);
}
}
__exportStar(require("./datasources"), exports);
var supergraphManagers_2 = require("./supergraphManagers");
Object.defineProperty(exports, "UplinkFetcherError", { enumerable: true, get: function () { return supergraphManagers_2.UplinkFetcherError; } });
//# sourceMappingURL=index.js.map