Why Apollo does not recommend using serviceList in Apollo Gateway in Production?

We are planning for a self-managed production setup with Apollo GraphQL Federation. I see 2 options.

  1. integrate CI/CD with rover CLI to create super graph
  2. use serviceList attribute on ApolloGateway so no Rover needed

both are not recommended by Apollo for prod. I’m interested in knowing bit of technical details about why they are not suitable for a containerized(k8) production env. where can we go wrong? Appreciate some light.

1 Like

Hello! One of the biggest advantages of a managed federation solution is that it prevents downtime for your federated gateway. Any time you need to update your serviceList to add, remove, or modify a subgraph, you need to restart your gateway to reflect the new configuration. Similarly with providing a Rover-composed schema, you need to restart the gateway to provide the updated schema via the supergraphSdl constructor option.

This is not the case for managed federation, where your gateway regularly polls an external resource (most commonly the Apollo Uplink) for an updated configuration and applies it at runtime. This means that your API stays up even as you modify underlying services.

More benefits of managed federation are described in this documentation article.

2 Likes

That’s sadly not possible for a lot of us that require all solutions to be on-premise with no traffic leaving our network. I hope that upcoming Federation rework levels the playing field so on-premise gets equal love (compared to managed Federation).

2 Likes

Hi @StephenBarlow - can you clarify please. Is it possible to have the external resource that the gateway polls to be something that is managed by our own infrastructure/cloud provider…for example a supergraph that has been composed and put in an s3 bucket? And on that I saw on the documents for the rover cli supergraph compose command (Working with supergraphs - Rover CLI - Apollo GraphQL Docs) that what it generates is not yet consumable by Apollo tools. Is there a way then with the rover cli or something else to generate the overall schema/supergraph from the subgraphs so that the gateway will understand it? Thanks :slight_smile:

1 Like

Actually Im pretty sure it doesnt interrogate all the services for each inbound query. I believe the primary negatives for using serviceList:

  1. During the Apollo Gateway service startup – every service contributing to your federated graph must be up and able to be queried by the gateway, else it will fail to startup.

  2. If you have in set to poll for updates (ie: via expermental_pollInterval) if any service is not up, then it will be unable to compose the supergraph and update until all services are available yet again.

1 Like

After some further investigation I got the answer to my own question. The Rover CLI supergraph command will generate a file that can be understood by the gateway. Then there are some “experimental_” properties that can be set on the GatewayConfig object. Here is some code

import { GatewayConfig } from '@apollo/gateway'
import fs from 'fs';

export const gatewayConfig: GatewayConfig = {
  experimental_pollInterval: 10000,
  experimental_updateSupergraphSdl: async(config) => {
    
    console.log('reading supergraphSdl file');
    // here you could read from say AWS S3 or wherever you want
    const supergraphSdl = fs.readFileSync('prod-schema.graphql', {encoding: 'utf-8'})

    return {
      id: new Date().toISOString(),
      supergraphSdl
    }
  }
};

and then in the gatweay startup…

import 'reflect-metadata';
import { ApolloServer } from 'apollo-server';
import { ApolloGateway } from '@apollo/gateway';
import { listen as userListen } from './user-subgraph/index'
import { listen as transactionsListen } from './transactions-subgraph/index'
import { listen as paymentsListen } from './payments-subgraph/index'
import { gatewayConfig } from './gatewayConfig'


async function bootstrap() {

  const gateway = new ApolloGateway(gatewayConfig);  

  const server = new ApolloServer({
    gateway,
    tracing: false,
    playground: true,
    subscriptions: false
  });

  await Promise.all([
    userListen(3001),
    transactionsListen(3002),
    paymentsListen(3003)
  ]);

  server.listen({ port: 3000 }).then(({ url }) => {
    console.log(`Apollo Gateway ready at ${url}`);
  });
}

bootstrap().catch(console.error);

@StephenBarlow what is the plan for the “experimental_pollInterval” and “experimental_updateSupergraphSdl” config options? Will they be kepts and made not experimental? Thanks :slight_smile:

There used to be an option in Federation, Gateway.load() which would tell the gateway to refetch the schema. This option was removed in version 2.23 and we still don’t understand why. We also are trying to understand why polling for changes is becoming the norm over pushing/triggering when there is a change. The loadI() option obviously does nothing for changing the paths or numbers of sub-graphs, a reload is required for that. Using gateway.load() was for the most part a very efficient pattern. Though our gateway deploy (cd) is quite fast and downtime isn’t experienced.