fix(health): add Supabase keepalive ping to GET / health check
UptimeRobot pings GET / every 5 minutes. Previously static response only kept Node process alive but let Supabase connection pool go cold. Now executes a lightweight HEAD query (profiles, limit 1) to maintain DB connection warmth. Always returns 200 with db status field for observability. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b5980ccce2
commit
fa06daace8
1 changed files with 59 additions and 38 deletions
97
src/index.ts
97
src/index.ts
|
|
@ -1,50 +1,71 @@
|
|||
import 'dotenv/config'
|
||||
import { Hono } from 'hono'
|
||||
import { cors } from 'hono/cors'
|
||||
import { serve } from '@hono/node-server'
|
||||
import { createNodeWebSocket } from '@hono/node-ws'
|
||||
import authRoutes from './routes/auth.js'
|
||||
import plansRoutes from './routes/plans.js'
|
||||
import simulationsRoutes from './routes/simulations.js'
|
||||
import sujetsRoutes from './routes/sujets.js'
|
||||
import correctionsRoutes from './routes/corrections.js'
|
||||
import stripeRoutes from './routes/stripe.js'
|
||||
import createT2LiveRoutes from './routes/t2live.js'
|
||||
import usersRoutes from './routes/users.js'
|
||||
import "dotenv/config";
|
||||
import { Hono } from "hono";
|
||||
import { cors } from "hono/cors";
|
||||
import { serve } from "@hono/node-server";
|
||||
import { createNodeWebSocket } from "@hono/node-ws";
|
||||
import authRoutes from "./routes/auth.js";
|
||||
import plansRoutes from "./routes/plans.js";
|
||||
import simulationsRoutes from "./routes/simulations.js";
|
||||
import sujetsRoutes from "./routes/sujets.js";
|
||||
import correctionsRoutes from "./routes/corrections.js";
|
||||
import stripeRoutes from "./routes/stripe.js";
|
||||
import createT2LiveRoutes from "./routes/t2live.js";
|
||||
import usersRoutes from "./routes/users.js";
|
||||
import { supabase } from "./lib/supabase.js";
|
||||
|
||||
const app = new Hono()
|
||||
const { upgradeWebSocket, injectWebSocket } = createNodeWebSocket({ app })
|
||||
const app = new Hono();
|
||||
const { upgradeWebSocket, injectWebSocket } = createNodeWebSocket({ app });
|
||||
|
||||
app.use(
|
||||
'*',
|
||||
"*",
|
||||
cors({
|
||||
origin: [
|
||||
'https://expria.app',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:5174',
|
||||
"https://expria.app",
|
||||
"http://localhost:5173",
|
||||
"http://localhost:5174",
|
||||
],
|
||||
allowMethods: ['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'],
|
||||
allowHeaders: ['Content-Type', 'Authorization', 'X-Api-Version'],
|
||||
})
|
||||
)
|
||||
allowMethods: ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"],
|
||||
allowHeaders: ["Content-Type", "Authorization", "X-Api-Version"],
|
||||
}),
|
||||
);
|
||||
|
||||
app.get('/', (c) => {
|
||||
return c.json({ message: 'Expria API — OK' }, 200)
|
||||
})
|
||||
// Health check — exécute un SELECT 1 léger sur Supabase pour garder le pool
|
||||
// de connexions DB actif (ping UptimeRobot toutes les 5 min sur Render Starter).
|
||||
// Le endpoint retourne toujours 200 (liveness) ; le champ `db` reporte l'état
|
||||
// réel de la connexion pour observabilité.
|
||||
const HEALTH_DB_TIMEOUT_MS = 5000;
|
||||
|
||||
app.route('/auth', authRoutes)
|
||||
app.route('/plans', plansRoutes)
|
||||
app.route('/simulations', simulationsRoutes)
|
||||
app.route('/sujets', sujetsRoutes)
|
||||
app.route('/corrections', correctionsRoutes)
|
||||
app.route('/stripe', stripeRoutes)
|
||||
app.route('/t2', createT2LiveRoutes(upgradeWebSocket))
|
||||
app.route('/users', usersRoutes)
|
||||
app.get("/", async (c) => {
|
||||
const probe = supabase.from("profiles").select("id", { head: true }).limit(1);
|
||||
const timeout = new Promise<{ error: Error }>((resolve) =>
|
||||
setTimeout(
|
||||
() => resolve({ error: new Error("HEALTH_DB_TIMEOUT") }),
|
||||
HEALTH_DB_TIMEOUT_MS,
|
||||
),
|
||||
);
|
||||
|
||||
const port = Number(process.env.PORT) || 3000
|
||||
try {
|
||||
const result = await Promise.race([probe, timeout]);
|
||||
const db = "error" in result && result.error ? "error" : "connected";
|
||||
return c.json({ message: "Expria API — OK", db }, 200);
|
||||
} catch {
|
||||
return c.json({ message: "Expria API — OK", db: "error" }, 200);
|
||||
}
|
||||
});
|
||||
|
||||
app.route("/auth", authRoutes);
|
||||
app.route("/plans", plansRoutes);
|
||||
app.route("/simulations", simulationsRoutes);
|
||||
app.route("/sujets", sujetsRoutes);
|
||||
app.route("/corrections", correctionsRoutes);
|
||||
app.route("/stripe", stripeRoutes);
|
||||
app.route("/t2", createT2LiveRoutes(upgradeWebSocket));
|
||||
app.route("/users", usersRoutes);
|
||||
|
||||
const port = Number(process.env.PORT) || 3000;
|
||||
|
||||
const server = serve({ fetch: app.fetch, port }, () => {
|
||||
console.log(`Expria API listening on port ${port}`)
|
||||
})
|
||||
console.log(`Expria API listening on port ${port}`);
|
||||
});
|
||||
|
||||
injectWebSocket(server)
|
||||
injectWebSocket(server);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue