Skip to content

Health Checks

Slingshot mounts two health endpoints automatically — one for liveness, one for readiness. Point your load balancer at the first to know “is the process up?” and your Kubernetes readiness probe at the second to know “is the process actually ready to take traffic?”.

GET /health is a cheap liveness check. It returns { status: "ok", timestamp: "..." } as long as the Hono server is responding — no dependencies are touched. Use it anywhere a fast boolean answer is enough.

GET /health/ready is a dependency-aware readiness check. It walks the resolved infrastructure attached to the SlingshotContext and exercises each one. Today that includes Postgres (connection latency, pool stats, query stats); future stores plug in here without needing a config flag. The endpoint returns 200 with status: "ok" when every probed dependency is healthy, or 503 with status: "degraded" when one fails — the response body always lists which check failed.

Both routes are registered before any plugin runs, so they keep responding even if a plugin errors during boot.

deployment.yaml
livenessProbe:
httpGet: { path: /health, port: 3000 }
periodSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet: { path: /health/ready, port: 3000 }
periodSeconds: 10
failureThreshold: 2

The liveness probe should never check dependencies — Kubernetes restarts the pod when it fails, and a flapping database would take your whole fleet down. The readiness probe is the right place for dependency checks; failing it just removes the pod from the load balancer until things recover.

The framework owns /health and /health/ready. To add app-specific checks (Stripe API reachability, an internal queue, a feature flag service) write a small plugin that registers a new route:

src/plugins/customHealth.ts
// @skip-typecheck
import { type SlingshotPlugin, createRouter } from '@lastshotlabs/slingshot';
export const customHealthPlugin: SlingshotPlugin = {
name: 'custom-health',
routes(ctx) {
const router = createRouter();
router.get('/health/stripe', async c => {
const ok = await pingStripe();
return c.json({ status: ok ? 'ok' : 'degraded' }, ok ? 200 : 503);
});
ctx.app.route('/', router);
},
};
declare function pingStripe(): Promise<boolean>;

Keep the response shape consistent with the framework’s checks (status, timestamp, optional details) so your monitoring tooling can treat them uniformly.