Add deploy-ready health checks
This commit is contained in:
@@ -85,4 +85,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
cd /docker/FlockPal
|
cd /docker/FlockPal
|
||||||
docker compose -f docker-compose.prod.yml up -d --build
|
docker compose -f docker-compose.prod.yml up -d --build --wait --wait-timeout 180
|
||||||
|
|
||||||
|
- name: Verify production API readiness
|
||||||
|
run: |
|
||||||
|
set -e
|
||||||
|
cd /docker/FlockPal
|
||||||
|
docker compose -f docker-compose.prod.yml exec -T backend node dist/healthcheck.js api-ready
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import nodemailer, { type SendMailOptions } from 'nodemailer';
|
|||||||
import Stripe from 'stripe';
|
import Stripe from 'stripe';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { db } from './db/client.js';
|
||||||
import { ensureSchema } from './db/schema.js';
|
import { ensureSchema } from './db/schema.js';
|
||||||
import { adoptionReportQueueEvents, enqueueAdoptionReportJob } from './queues/adoptionReportQueue.js';
|
import { adoptionReportQueueEvents, enqueueAdoptionReportJob } from './queues/adoptionReportQueue.js';
|
||||||
import { enqueueBirdMilestoneReminderJob, getBirdMilestoneReminderQueueCounts } from './queues/birdMilestoneReminderQueue.js';
|
import { enqueueBirdMilestoneReminderJob, getBirdMilestoneReminderQueueCounts } from './queues/birdMilestoneReminderQueue.js';
|
||||||
@@ -2514,6 +2515,24 @@ app.get('/api/health', (_req: Request, res: Response) => {
|
|||||||
res.json({ ok: true });
|
res.json({ ok: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/api/health/live', (_req: Request, res: Response) => {
|
||||||
|
res.json({ ok: true, status: 'live' });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/health/ready', async (_req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
await Promise.all([
|
||||||
|
db.query('SELECT 1'),
|
||||||
|
getBirdMilestoneReminderQueueCounts(),
|
||||||
|
getMedicationReminderQueueCounts(),
|
||||||
|
]);
|
||||||
|
res.json({ ok: true, status: 'ready' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Readiness check failed', error);
|
||||||
|
res.status(503).json({ ok: false, status: 'not_ready' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
app.get('/api/metrics', requireAuth, requireAdmin, async (_req: Request, res: Response, next: NextFunction) => {
|
app.get('/api/metrics', requireAuth, requireAdmin, async (_req: Request, res: Response, next: NextFunction) => {
|
||||||
const memoryUsage = process.memoryUsage();
|
const memoryUsage = process.memoryUsage();
|
||||||
const averageDurationMs = requestMetrics.totalRequests > 0 ? requestMetrics.totalDurationMs / requestMetrics.totalRequests : 0;
|
const averageDurationMs = requestMetrics.totalRequests > 0 ? requestMetrics.totalDurationMs / requestMetrics.totalRequests : 0;
|
||||||
|
|||||||
@@ -95,6 +95,12 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:5000/api/health/ready').then(r => { if (!r.ok) process.exit(1) }).catch(() => process.exit(1))\""]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
ports:
|
ports:
|
||||||
- "5000:5000"
|
- "5000:5000"
|
||||||
command: >
|
command: >
|
||||||
@@ -103,6 +109,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./backend:/app
|
- ./backend:/app
|
||||||
- /app/node_modules
|
- /app/node_modules
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
worker:
|
worker:
|
||||||
build:
|
build:
|
||||||
|
|||||||
Reference in New Issue
Block a user