Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions backend/api/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import profileRoutes from './routes/profileRoutes.js';
import loadRoutes from './routes/loadRoutes.js';
import truckRoutes from './routes/truckRoutes.js';
import authRoutes from './routes/authRoutes.js';
import healthRoutes from './routes/healthRoutes.js';

import logger from './middleware/logger.js';
import { requestIdMiddleware, requestLogger } from './middleware/requestId.js';
Expand Down Expand Up @@ -172,18 +173,7 @@ app.use('/api/v1/trips', tripRoutes);
// ============================================================================
// REST API ROUTING
// ============================================================================
app.get('/api/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date(),
service: 'Truxify API',
uptime: process.uptime(),
env: {
bypass_auth: process.env.BYPASS_AUTH === 'true',
node_version: process.version
}
});
});
app.use('/api/health', healthRoutes);

app.use('/api/orders', orderRoutes);
app.use('/api/driver', driverRoutes);
Expand Down
97 changes: 97 additions & 0 deletions backend/api/src/routes/healthRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import express from 'express';
import { supabase, mongoDb, redisClient, firebaseAdmin } from '../config/db.js';

const router = express.Router();

const DEFAULT_TIMEOUT_MS = 400;
const _parsedTimeout = Number(process.env.HEALTHCHECK_TIMEOUT_MS);
const CHECK_TIMEOUT_MS =
Number.isFinite(_parsedTimeout) && _parsedTimeout > 0 ? _parsedTimeout : DEFAULT_TIMEOUT_MS;

function withTimeout(promise) {
let timer;
return Promise.race([
promise,
new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error('healthcheck timeout')), CHECK_TIMEOUT_MS);
}),
]).finally(() => clearTimeout(timer));
}

async function checkSupabase() {
if (!supabase) return 'not_configured';
try {
const { error } = await withTimeout(
supabase.from('profiles').select('id').limit(1)
);
return error ? 'failed' : 'connected';
} catch {
return 'failed';
}
}

async function checkMongo() {
if (!mongoDb) return 'not_configured';
try {
await withTimeout(mongoDb.admin().ping());
return 'connected';
} catch {
return 'failed';
}
}

async function checkRedis() {
if (!redisClient) return 'not_configured';
try {
const reply = await withTimeout(redisClient.ping());
return reply === 'PONG' ? 'connected' : 'failed';
} catch {
return 'failed';
}
}

function checkFirebase() {
return firebaseAdmin ? 'configured' : 'not_configured';
}

function checkPolygon() {
return process.env.POLYGON_RPC_URL ? 'configured' : 'not_configured';
}

const CRITICAL_UNHEALTHY = new Set(['failed', 'not_configured']);

// GET /api/health — full dependency check; returns 503 when a critical service fails
router.get('/', async (req, res) => {
const [supabaseStatus, mongoStatus, redisStatus] = await Promise.all([
checkSupabase(),
checkMongo(),
checkRedis(),
]);
Comment thread
nyxsky404 marked this conversation as resolved.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const services = {
supabase: supabaseStatus,
mongodb: mongoStatus,
redis: redisStatus,
firebase: checkFirebase(),
polygon: checkPolygon(),
};

const criticalFailed =
CRITICAL_UNHEALTHY.has(supabaseStatus) || CRITICAL_UNHEALTHY.has(mongoStatus);

const status = criticalFailed ? 'degraded' : 'ok';
const httpStatus = criticalFailed ? 503 : 200;
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return res.status(httpStatus).json({
status,
services,
uptime: process.uptime(),
});
});

// GET /api/health/live — liveness probe; always 200 as long as the process is up
router.get('/live', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});

export default router;
6 changes: 6 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ services:
- mongo
- redis
- db
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:5000/api/health/live || curl -sf http://localhost:5000/api/health/live"]
interval: 30s
timeout: 5s
retries: 5
start_period: 15s
Comment thread
nyxsky404 marked this conversation as resolved.

ml-engine:
build:
Expand Down
Loading