Health Check
Yoga is aware of the usefulness of a health check and gives the user maximum possibilities to use the built-in check and create a “readiness” check through a simple plugin.
Types of health checks
There are two types of health checks: liveliness and readiness, they both are a health check but convey a different meaning:
- Liveliness checks whether the service is alive and running
- Readiness checks whether the service is ready to perform work
The difference is that a service can be live but not ready - for example, server has started and is accepting requests (alive), but the read replica it uses is still unavailable (not ready).
A liveliness check is something Yoga can offer out-of-the-box because Yoga is a server and Yoga knows when it’s alive. However, a readiness check is something Yoga cannot figure out on its own, it is a check requiring user-land context.
Having said this, Yoga has a /health
route which is used for liveliness check and offers a
useReadinessCheck
plugin allowing you to implement your own readiness check.
Liveliness
By default, you can check whether Yoga is alive by issuing a request to the /health
endpoint and
expecting the response 200 OK
.
Of course, you can change this endpoint through the healthCheckEndpoint
option.
import { createServer } from 'node:http'
import { createYoga } from 'graphql-yoga'
import { schema } from './my-service'
const yoga = createYoga({
schema,
healthCheckEndpoint: '/live'
})
const server = createServer(yoga)
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
A successful response is just 200 OK
without a body.
Readiness
Additionally, you might want an endpoint which checks whether the services powering Yoga are ready to perform work.
Since this check requires more context that Yoga cannot assume, you’re recommended to use the core
useReadinessPlugin
and implement your own check.
import { createServer } from 'node:http'
import { createYoga, useReadinessCheck } from 'graphql-yoga'
import { checkDbAvailable, schema } from './my-service'
const yoga = createYoga({
schema,
plugins: [
useReadinessCheck({
endpoint: '/ready', // default
check: async () => {
// if resolves, respond with 200 OK
// if throw, respond with 503 Service Unavailable and error message as plaintext in body
await checkDbAvailable()
}
})
]
})
const server = createServer(yoga)
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})
Throwing an instance of Error
in the check
function will have Yoga respond with
503 Service Unavailable
with the error’s message in the body.
Please make sure that thrown errors are not leaking sensitive information in production environments.
Alternatively, you can simply return false
from the check
function to have Yoga respond with
just 503 Service Unavailable
and no body. This way you can make sure nothing sensitive leaks ever.
import { createServer } from 'node:http'
import { createYoga, useReadinessCheck } from 'graphql-yoga'
import { checkDbAvailable, schema } from './my-service'
const yoga = createYoga({
schema,
plugins: [
useReadinessCheck({
endpoint: '/ready', // default
check: async () => {
try {
await checkDbAvailable()
// if true, respond with 200 OK
return false
} catch (err) {
// log the error on the server for debugging purposes
console.error(err)
// if false, respond with 503 Service Unavailable and no bdy
return false
}
}
})
]
})
const server = createServer(yoga)
server.listen(4000, () => {
console.info('Server is running on http://localhost:4000/graphql')
})