Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 6x 6x 6x 6x 7x 7x 6x 6x 6x 6x 6x 6x 7x 7x 1x 1x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 30x 30x 30x 6x 6x 6x 6x 6x 7x 1x 1x 6x 6x 6x 6x 6x 6x 6x 6x 7x 1x 7x 1x 1x 6x 6x 7x 7x 7x 7x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x | export const dynamic = "force-dynamic";
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import { getMetricsSummary } from '@/lib/database/metrics';
interface HealthCheckResult {
status: 'healthy' | 'degraded' | 'unhealthy';
timestamp: string;
checks: {
connection: {
status: 'pass' | 'fail';
latency: number;
message?: string;
};
queryPerformance: {
status: 'pass' | 'warn' | 'fail';
avgQueryTime: number;
slowQueryPercentage: number;
};
tableHealth: {
status: 'pass' | 'warn' | 'fail';
tables: { name: string; count: number; healthy: boolean }[];
};
};
}
/**
* GET /api/health/db
*
* Dedicated database health check endpoint.
* Returns detailed information about database connectivity and performance.
*/
export async function GET() {
const result: HealthCheckResult = {
status: 'healthy',
timestamp: new Date().toISOString(),
checks: {
connection: {
status: 'pass',
latency: 0
},
queryPerformance: {
status: 'pass',
avgQueryTime: 0,
slowQueryPercentage: 0
},
tableHealth: {
status: 'pass',
tables: []
}
}
};
try {
// Check 1: Database Connection
const connectionStart = performance.now();
await prisma.$queryRaw`SELECT 1`;
const connectionLatency = performance.now() - connectionStart;
result.checks.connection.latency = Math.round(connectionLatency);
if (connectionLatency > 500) {
result.checks.connection.status = 'fail';
result.checks.connection.message = 'Connection latency too high';
} else if (connectionLatency > 100) {
result.checks.connection.status = 'pass';
result.checks.connection.message = 'Connection latency elevated';
}
// Check 2: Query Performance Metrics
const metrics = getMetricsSummary();
result.checks.queryPerformance.avgQueryTime = metrics.avgQueryTime;
result.checks.queryPerformance.slowQueryPercentage = metrics.slowQueryPercentage;
if (metrics.avgQueryTime > 100 || metrics.slowQueryPercentage > 10) {
result.checks.queryPerformance.status = 'fail';
} else if (metrics.avgQueryTime > 50 || metrics.slowQueryPercentage > 5) {
result.checks.queryPerformance.status = 'warn';
}
// Check 3: Table Health (verify key tables are accessible)
const tableChecks = await Promise.allSettled([
prisma.product.count(),
prisma.user.count(),
prisma.order.count(),
prisma.review.count(),
prisma.category.count(),
]);
const tableNames = ['products', 'users', 'orders', 'reviews', 'categories'];
const tableResults = tableChecks.map((check, index) => ({
name: tableNames[index],
count: check.status === 'fulfilled' ? check.value : -1,
healthy: check.status === 'fulfilled'
}));
result.checks.tableHealth.tables = tableResults;
const unhealthyTables = tableResults.filter(t => !t.healthy);
if (unhealthyTables.length > 0) {
result.checks.tableHealth.status = 'fail';
}
// Determine overall status
const statuses = [
result.checks.connection.status,
result.checks.queryPerformance.status,
result.checks.tableHealth.status,
];
if (statuses.includes('fail')) {
result.status = 'unhealthy';
} else if (statuses.includes('warn')) {
result.status = 'degraded';
}
return NextResponse.json(result, {
status: result.status === 'unhealthy' ? 503 : 200,
headers: {
'Cache-Control': 'no-store, no-cache, must-revalidate'
}
});
} catch (error) {
result.status = 'unhealthy';
result.checks.connection.status = 'fail';
result.checks.connection.message = error instanceof Error ? error.message : 'Unknown error';
return NextResponse.json(result, {
status: 503,
headers: {
'Cache-Control': 'no-store, no-cache, must-revalidate'
}
});
}
}
|