Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Production Ready Apollo Gateway for GraphQL Services issue #10

Open
jay-korsi opened this issue Jul 1, 2021 · 1 comment
Open

Production Ready Apollo Gateway for GraphQL Services issue #10

jay-korsi opened this issue Jul 1, 2021 · 1 comment

Comments

@jay-korsi
Copy link

Hi Team,

We are new to GraphQL and we built couple of GraphQl Services using Netflix DGS.

Now we would like to federate those services into single endpoint and started working on it by cloning the apollo gateway federation by netflix example dgs-federation-example/apollo-gateway at master · Netflix/dgs-federation-example · GitHub.

This works perfectly fine on my local machine. But When we deploy the node js app to our AWS EKS env, I am not sure how can I access the apollo server. I always see the Server ready at http://localhost:4000/

I have exposed the port 4000 as well but no use.

Here is my code for creating the apollo server. Please help. I have been trying it for couple of weeks now. I didn’t find a production ready federation example also.

'use strict'

const https = require('https')
const http = require('http')
const config = require('config')
const app = require('./app.js')
const log = require('<custom_logger>')
const { ApolloServer } = require('apollo-server')
const { ApolloGateway, RemoteGraphQLDataSource } = require('@apollo/gateway')
var os = require("os");

var hostname = os.hostname();
console.log("hostname:"+hostname)
let httpListenerPort = 8080
let httpsListenerPort = 8443

log.info('NODE_ENV: ' + config.util.getEnv('NODE_ENV'))
log.info('NODE_APP_INSTANCE: ' + config.util.getEnv('NODE_APP_INSTANCE'))
log.info('NODE_CONFIG_DIR: ' + config.util.getEnv('NODE_CONFIG_DIR'))
log.levels(
  0,
  process.env.LOG_LEVEL
    ? parseInt(process.env.LOG_LEVEL, 10)
    : 'info'
)

log.info('log.levels(): ' + log.levels())

const gateway = new ApolloGateway({
  serviceList: [
    {
      name: 'service1',
      url: '<link_to_service1>/graphql'
    },
    {
      name: 'service2',
      url: '<link_to_service2>/graphql'
    },
    {
      name: 'service3',
      url: '<link_to_service3>/graphql'
    },
    {
      name: 'service4',
      url: '<link_to_service4>/graphql'
    }
  ],
  introspectionHeaders: {
    apikey: process.env.API_KEY
  },
  buildService ({ url }) {
    return new RemoteGraphQLDataSource({
      url,
      willSendRequest ({ request }) {
        request.http.headers.set('apikey', process.env.API_KEY)
      }
    })
  }
})

const httpServer = http.createServer(app).listen(httpListenerPort, () => {
  log.info('app is listening at localhost:' + httpListenerPort)
})

const httpsServer = https
  .createServer(<api_certs>, app)
  .listen(httpsListenerPort, () => {
    log.info('app is listening at localhost:' + httpsListenerPort)
  })

const server = new ApolloServer({
  gateway,
  subscriptions: false,
  tracing: true,
  introspection: true, // TO ENABLE PLAYGROUND IN PRODUCTION
  playground: true, // TO ENABLE PLAYGROUND IN PRODUCTION
  onHealthCheck: () => {
    return new Promise(resolve => {
      resolve()
    })
  }
})


server.listen(4000).then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`)
  console.log(
    `Try your health check at: ${url}.well-known/apollo/server-health`,
  );
}).catch(err => {console.error(err)});

function timeoutExit (seconds = 5) {
  const timeout = setTimeout(() => {
    log.fatal(
      { exitCode: process.exitCode },
      `Application did not gracefully shutdown in ${seconds} seconds. Forcibly terminating.`
    )
    process.exit()
  }, seconds * 1000)
  // un-ref the timer so Node.js exits even with this running timer
  timeout.unref()
  return timeout
}

function closeServers () {
  httpServer.close(() => {
    log.info('HTTP server is shutdown')
  })
  httpsServer.close(() => {
    log.info('HTTPS server is shutdown')
  })
}

process.on('SIGTERM', () => {
  log.info('SIGTERM issued...app is shutting down')
  closeServers()
  timeoutExit()
})

process.on('uncaughtException', error => {
  log.fatal(
    error,
    'Uncaught Exception! The server is now in an unrecoverable state. Terminating...'
  )
  closeServers()
  // the app should exit on its own when there are no daemons running nor events on the event loop

  // forcibly terminate if haven't done so gracefully within timeout
  timeoutExit()
})

process.on('unhandledRejection', (reason, promise) => {
  log.error(
    {
      err: reason,
      promise
    },
    'Unhandled Promise Rejection'
  )
})

Not having any other configs for playground too. Have health check for http server only on top of it. Please suggest on how to spin the apollo server up and running in our K8s environment

@jonckvanderkogel
Copy link

You can find the answer here. In essence, if you want to deploy locally you have to create a listing of your services, if you want to deploy using Apollo Studio you should remove those service references in the constructor and rather use Rover CLI to register your services to Apollo Studio. Your gateway will then automatically discover them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants