feat: graceful shutdown (#205)
* feat: graceful shutdown * comments by coderabbit * fix
This commit is contained in:
committed by
GitHub
parent
5092b6ae51
commit
ca4a880acd
@@ -1,83 +1,60 @@
|
||||
import { round } from '@openpanel/common';
|
||||
import { TABLE_NAMES, chQuery, db } from '@openpanel/db';
|
||||
import { eventsQueue } from '@openpanel/queue';
|
||||
import { isShuttingDown } from '@/utils/graceful-shutdown';
|
||||
import { chQuery, db } from '@openpanel/db';
|
||||
import { getRedisCache } from '@openpanel/redis';
|
||||
import type { FastifyReply, FastifyRequest } from 'fastify';
|
||||
|
||||
async function withTimings<T>(promise: Promise<T>) {
|
||||
const time = performance.now();
|
||||
try {
|
||||
const data = await promise;
|
||||
return {
|
||||
time: round(performance.now() - time, 2),
|
||||
data,
|
||||
} as const;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// For docker compose healthcheck
|
||||
export async function healthcheck(
|
||||
request: FastifyRequest,
|
||||
reply: FastifyReply,
|
||||
) {
|
||||
if (process.env.DISABLE_HEALTHCHECK) {
|
||||
return reply.status(200).send({
|
||||
ok: true,
|
||||
});
|
||||
}
|
||||
const redisRes = await withTimings(getRedisCache().ping());
|
||||
const dbRes = await withTimings(db.project.findFirst());
|
||||
const queueRes = await withTimings(eventsQueue.getCompleted());
|
||||
const chRes = await withTimings(
|
||||
chQuery(
|
||||
`SELECT * FROM ${TABLE_NAMES.events} WHERE created_at > now() - INTERVAL 10 MINUTE LIMIT 1`,
|
||||
),
|
||||
);
|
||||
const status = redisRes && dbRes && queueRes && chRes ? 200 : 500;
|
||||
try {
|
||||
const redisRes = await getRedisCache().ping();
|
||||
const dbRes = await db.project.findFirst();
|
||||
const chRes = await chQuery('SELECT 1');
|
||||
const status = redisRes && dbRes && chRes ? 200 : 503;
|
||||
|
||||
reply.status(status).send({
|
||||
redis: redisRes
|
||||
? {
|
||||
ok: redisRes.data === 'PONG',
|
||||
time: `${redisRes.time}ms`,
|
||||
}
|
||||
: null,
|
||||
db: dbRes
|
||||
? {
|
||||
ok: !!dbRes.data,
|
||||
time: `${dbRes.time}ms`,
|
||||
}
|
||||
: null,
|
||||
queue: queueRes
|
||||
? {
|
||||
ok: !!queueRes.data,
|
||||
time: `${queueRes.time}ms`,
|
||||
}
|
||||
: null,
|
||||
ch: chRes
|
||||
? {
|
||||
ok: !!chRes.data,
|
||||
time: `${chRes.time}ms`,
|
||||
}
|
||||
: null,
|
||||
});
|
||||
}
|
||||
|
||||
export async function healthcheckQueue(
|
||||
request: FastifyRequest,
|
||||
reply: FastifyReply,
|
||||
) {
|
||||
const count = await eventsQueue.getWaitingCount();
|
||||
if (count > 40) {
|
||||
reply.status(500).send({
|
||||
ok: false,
|
||||
count,
|
||||
reply.status(status).send({
|
||||
ready: status === 200,
|
||||
redis: redisRes === 'PONG',
|
||||
db: !!dbRes,
|
||||
ch: chRes && chRes.length > 0,
|
||||
});
|
||||
} else {
|
||||
reply.status(200).send({
|
||||
ok: true,
|
||||
count,
|
||||
} catch (error) {
|
||||
return reply.status(503).send({
|
||||
ready: false,
|
||||
reason: 'dependencies not ready',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Kubernetes - Liveness probe - returns 200 if process is alive
|
||||
export async function liveness(request: FastifyRequest, reply: FastifyReply) {
|
||||
return reply.status(200).send({ live: true });
|
||||
}
|
||||
|
||||
// Kubernetes - Readiness probe - returns 200 only when accepting requests, 503 during shutdown
|
||||
export async function readiness(request: FastifyRequest, reply: FastifyReply) {
|
||||
if (isShuttingDown()) {
|
||||
return reply.status(503).send({ ready: false, reason: 'shutting down' });
|
||||
}
|
||||
|
||||
// Perform lightweight dependency checks for readiness
|
||||
const redisRes = await getRedisCache().ping();
|
||||
const dbRes = await db.project.findFirst();
|
||||
const chRes = await chQuery('SELECT 1');
|
||||
|
||||
const isReady = redisRes && dbRes && chRes;
|
||||
|
||||
if (!isReady) {
|
||||
return reply.status(503).send({
|
||||
ready: false,
|
||||
reason: 'dependencies not ready',
|
||||
redis: redisRes === 'PONG',
|
||||
db: !!dbRes,
|
||||
ch: chRes && chRes.length > 0,
|
||||
});
|
||||
}
|
||||
|
||||
return reply.status(200).send({ ready: true });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user