@apollo/gateway
Version:
214 lines • 10.5 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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UplinkSupergraphManager = void 0;
const makeFetchHappen = __importStar(require("make-fetch-happen"));
const resolvable_1 = __importDefault(require("@josephg/resolvable"));
const logger_1 = require("../../logger");
const loadSupergraphSdlFromStorage_1 = require("./loadSupergraphSdlFromStorage");
class UplinkSupergraphManager {
constructor({ apiKey, graphRef, debug, logger, uplinkEndpoints, fallbackPollIntervalInMs, maxRetries, initialMaxRetries, fetcher, shouldRunSubgraphHealthcheck, onFailureToFetchSupergraphSdlDuringInit, onFailureToFetchSupergraphSdlAfterInit, }) {
this.uplinkEndpoints = UplinkSupergraphManager.getUplinkEndpoints();
this.fetcher = makeFetchHappen.defaults();
this.requestTimeoutMs = UplinkSupergraphManager.DEFAULT_REQUEST_TIMEOUT_MS;
this.pollIntervalMs = UplinkSupergraphManager.MIN_POLL_INTERVAL_MS;
this.shouldRunSubgraphHealthcheck = false;
this.timerRef = null;
this.fetchCount = 0;
this.apiKey = apiKey;
this.graphRef = graphRef;
this.logger = logger !== null && logger !== void 0 ? logger : (0, logger_1.getDefaultLogger)(debug);
this.uplinkEndpoints = uplinkEndpoints !== null && uplinkEndpoints !== void 0 ? uplinkEndpoints : this.uplinkEndpoints;
this.maxRetries = maxRetries !== null && maxRetries !== void 0 ? maxRetries : this.uplinkEndpoints.length * 3 - 1;
this.initialMaxRetries = initialMaxRetries !== null && initialMaxRetries !== void 0 ? initialMaxRetries : this.maxRetries;
this.pollIntervalMs = fallbackPollIntervalInMs !== null && fallbackPollIntervalInMs !== void 0 ? fallbackPollIntervalInMs : this.pollIntervalMs;
this.fallbackPollIntervalInMs = fallbackPollIntervalInMs;
if (this.pollIntervalMs < UplinkSupergraphManager.MIN_POLL_INTERVAL_MS) {
this.logger.warn('Polling Apollo services at a frequency of less than once per 10 seconds (10000) is disallowed. Instead, the minimum allowed pollInterval of 10000 will be used. Please reconfigure your `fallbackPollIntervalInMs` accordingly. If this is problematic for your team, please contact support.');
this.pollIntervalMs = UplinkSupergraphManager.MIN_POLL_INTERVAL_MS;
}
this.fetcher = fetcher !== null && fetcher !== void 0 ? fetcher : this.fetcher;
this.shouldRunSubgraphHealthcheck =
shouldRunSubgraphHealthcheck !== null && shouldRunSubgraphHealthcheck !== void 0 ? shouldRunSubgraphHealthcheck : this.shouldRunSubgraphHealthcheck;
this.onFailureToFetchSupergraphSdlDuringInit =
onFailureToFetchSupergraphSdlDuringInit;
this.onFailureToFetchSupergraphSdlAfterInit =
onFailureToFetchSupergraphSdlAfterInit;
if (!!process.env.APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT) {
this.logger.warn('Out-of-band error reporting is no longer used by Apollo. You may remove the `APOLLO_OUT_OF_BAND_REPORTER_ENDPOINT` environment variable at your convenience.');
}
this.state = { phase: 'constructed' };
}
async initialize({ update, healthCheck }) {
this.update = update;
if (this.shouldRunSubgraphHealthcheck) {
this.healthCheck = healthCheck;
}
let initialSupergraphSdl = null;
try {
initialSupergraphSdl = await this.updateSupergraphSdl(this.initialMaxRetries);
if (!initialSupergraphSdl) {
throw new Error('Invalid supergraph schema supplied during initialization.');
}
}
catch (e) {
this.logUpdateFailure(e);
throw e;
}
this.state = { phase: 'initialized' };
this.beginPolling();
return {
supergraphSdl: initialSupergraphSdl,
cleanup: async () => {
if (this.state.phase === 'polling') {
await this.state.pollingPromise;
}
this.state = { phase: 'stopped' };
if (this.timerRef) {
clearTimeout(this.timerRef);
this.timerRef = null;
}
},
};
}
async nextFetch() {
if (this.state.phase !== 'polling') {
return;
}
return this.state.nextFetchPromise;
}
static getUplinkEndpoints() {
var _a;
const envEndpoints = (_a = process.env.APOLLO_SCHEMA_CONFIG_DELIVERY_ENDPOINT) === null || _a === void 0 ? void 0 : _a.split(',');
return envEndpoints !== null && envEndpoints !== void 0 ? envEndpoints : UplinkSupergraphManager.DEFAULT_UPLINK_ENDPOINTS;
}
async updateSupergraphSdl(maxRetries) {
var _a, _b;
let supergraphSdl;
try {
const result = await (0, loadSupergraphSdlFromStorage_1.loadSupergraphSdlFromUplinks)({
graphRef: this.graphRef,
apiKey: this.apiKey,
endpoints: this.uplinkEndpoints,
fetcher: this.fetcher,
compositionId: (_a = this.compositionId) !== null && _a !== void 0 ? _a : null,
maxRetries,
requestTimeoutMs: this.requestTimeoutMs,
roundRobinSeed: this.fetchCount++,
logger: this.logger,
});
this.mostRecentSuccessfulFetchAt = new Date();
this.logger.debug(`Received Uplink response. Has updated SDL? ${!!(result === null || result === void 0 ? void 0 : result.supergraphSdl)}`);
if (!result) {
return null;
}
this.compositionId = result.id;
supergraphSdl = result.supergraphSdl;
if (result === null || result === void 0 ? void 0 : result.minDelaySeconds) {
this.pollIntervalMs = result.minDelaySeconds * 1000;
if (this.fallbackPollIntervalInMs) {
this.pollIntervalMs = Math.max(this.pollIntervalMs, this.fallbackPollIntervalInMs);
}
}
}
catch (e) {
this.logger.debug(`Error fetching supergraphSdl from Uplink during phase '${this.state.phase}'`);
if (this.state.phase === 'constructed' &&
this.onFailureToFetchSupergraphSdlDuringInit) {
supergraphSdl = await this.onFailureToFetchSupergraphSdlDuringInit({
error: e,
graphRef: this.graphRef,
logger: this.logger,
fetchCount: this.fetchCount,
});
}
else if (this.state.phase === 'polling' &&
this.onFailureToFetchSupergraphSdlAfterInit) {
supergraphSdl = await this.onFailureToFetchSupergraphSdlAfterInit({
error: e,
graphRef: this.graphRef,
logger: this.logger,
fetchCount: this.fetchCount,
mostRecentSuccessfulFetchAt: this.mostRecentSuccessfulFetchAt,
});
if (!supergraphSdl) {
return null;
}
}
else {
throw e;
}
}
await ((_b = this.healthCheck) === null || _b === void 0 ? void 0 : _b.call(this, supergraphSdl));
return supergraphSdl;
}
beginPolling() {
this.state = { phase: 'polling' };
this.poll();
}
poll() {
if (this.state.phase !== 'polling') {
this.logger.debug(`Stopped polling Uplink [phase: ${this.state.phase}]`);
return;
}
this.state.nextFetchPromise = (0, resolvable_1.default)();
this.logger.debug(`Will poll Uplink after ${this.pollIntervalMs}ms [phase: ${this.state.phase}]`);
this.timerRef = setTimeout(async () => {
var _a, _b;
if (this.state.phase === 'polling') {
const pollingPromise = (0, resolvable_1.default)();
this.state.pollingPromise = pollingPromise;
try {
const supergraphSdl = await this.updateSupergraphSdl(this.maxRetries);
if (supergraphSdl) {
(_a = this.update) === null || _a === void 0 ? void 0 : _a.call(this, supergraphSdl);
}
}
catch (e) {
this.logUpdateFailure(e);
}
pollingPromise.resolve();
(_b = this.state.nextFetchPromise) === null || _b === void 0 ? void 0 : _b.resolve();
}
this.poll();
}, this.pollIntervalMs);
}
logUpdateFailure(e) {
var _a;
this.logger.error('UplinkSupergraphManager failed to update supergraph with the following error: ' +
((_a = e.message) !== null && _a !== void 0 ? _a : e));
}
}
exports.UplinkSupergraphManager = UplinkSupergraphManager;
UplinkSupergraphManager.DEFAULT_REQUEST_TIMEOUT_MS = 30000;
UplinkSupergraphManager.MIN_POLL_INTERVAL_MS = 10000;
UplinkSupergraphManager.DEFAULT_UPLINK_ENDPOINTS = [
'https://uplink.api.apollographql.com/',
'https://aws.uplink.api.apollographql.com/',
];
//# sourceMappingURL=index.js.map