|
| 1 | +import { Callout } from '@theguild/components' |
| 2 | + |
| 3 | +# Health check |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +## Types of health checks |
| 8 | + |
| 9 | +There are two types of health checks: **liveliness** and **readiness**, they both _are_ a health check but convey a different meaning: |
| 10 | + |
| 11 | +- **Liveliness** checks whether the service is alive and running |
| 12 | +- **Readiness** checks whether the service is ready to perform work |
| 13 | + |
| 14 | +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). |
| 15 | + |
| 16 | +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. |
| 17 | + |
| 18 | +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. |
| 19 | + |
| 20 | +### Liveliness |
| 21 | + |
| 22 | +By default, you can check whether Yoga is alive by issuing a request to the `/health` endpoint and expecting the response `200 OK`. |
| 23 | + |
| 24 | +Of course, you can change this endpoint through the `healthCheckEndpoint` option. |
| 25 | + |
| 26 | +```ts |
| 27 | +import { createYoga } from 'graphql-yoga' |
| 28 | +import { createServer } from 'node:http' |
| 29 | +import { schema } from './my-service' |
| 30 | + |
| 31 | +const yoga = createYoga({ |
| 32 | + schema, |
| 33 | + healthCheckEndpoint: '/live', |
| 34 | +}) |
| 35 | + |
| 36 | +const server = createServer(yoga) |
| 37 | +server.listen(4000, () => { |
| 38 | + console.info('Server is running on http://localhost:4000/graphql') |
| 39 | +}) |
| 40 | +``` |
| 41 | + |
| 42 | +A successful response is just `200 OK` without a body. |
| 43 | + |
| 44 | +### Readiness |
| 45 | + |
| 46 | +Additionally, you might want an endpoint which checks whether the services powering Yoga are ready to perform work. |
| 47 | + |
| 48 | +Since this check requires more context that Yoga cannot assume, you're recommended to use the core `useReadinessPlugin` and implement your own check. |
| 49 | + |
| 50 | +```ts |
| 51 | +import { createYoga, useReadinessCheck } from 'graphql-yoga' |
| 52 | +import { createServer } from 'node:http' |
| 53 | +import { schema, checkDbAvailable } from './my-service' |
| 54 | + |
| 55 | +const yoga = createYoga({ |
| 56 | + schema, |
| 57 | + plugins: [ |
| 58 | + useReadinessCheck({ |
| 59 | + endpoint: '/ready', // default |
| 60 | + check: async () => { |
| 61 | + // if resolves, respond with 200 OK |
| 62 | + // if throw, respond with 504 Service Unavailable and error message as plaintext in body |
| 63 | + await checkDbAvailable() |
| 64 | + }, |
| 65 | + }), |
| 66 | + ], |
| 67 | +}) |
| 68 | + |
| 69 | +const server = createServer(yoga) |
| 70 | +server.listen(4000, () => { |
| 71 | + console.info('Server is running on http://localhost:4000/graphql') |
| 72 | +}) |
| 73 | +``` |
| 74 | + |
| 75 | +Throwing an instance of `Error` in the `check` function will have Yoga respond with `504 Service Unavailable` with the error's message in the body. |
| 76 | + |
| 77 | +<Callout> |
| 78 | + Please make sure that thrown errors are not leaking sensitive information in |
| 79 | + production environments. |
| 80 | +</Callout> |
| 81 | + |
| 82 | +Alternatively, you can simply return `false` from the `check` function to have Yoga respond with just `504 Service Unavailable` and no body. This way you can make sure nothing sensitive leaks ever. |
| 83 | + |
| 84 | +```ts |
| 85 | +import { createYoga, useReadinessCheck } from 'graphql-yoga' |
| 86 | +import { createServer } from 'node:http' |
| 87 | +import { schema, checkDbAvailable } from './my-service' |
| 88 | + |
| 89 | +const yoga = createYoga({ |
| 90 | + schema, |
| 91 | + plugins: [ |
| 92 | + useReadinessCheck({ |
| 93 | + endpoint: '/ready', // default |
| 94 | + check: async () => { |
| 95 | + try { |
| 96 | + await checkDbAvailable() |
| 97 | + // if true, respond with 200 OK |
| 98 | + return false |
| 99 | + } catch (err) { |
| 100 | + // log the error on the server for debugging purposes |
| 101 | + console.error(err) |
| 102 | + // if false, respond with 504 Service Unavailable and no bdy |
| 103 | + return false |
| 104 | + } |
| 105 | + }, |
| 106 | + }), |
| 107 | + ], |
| 108 | +}) |
| 109 | + |
| 110 | +const server = createServer(yoga) |
| 111 | +server.listen(4000, () => { |
| 112 | + console.info('Server is running on http://localhost:4000/graphql') |
| 113 | +}) |
| 114 | +``` |
0 commit comments