Askr
Guides

Production Readiness

Use production readiness with the current published Askr packages.

  • @askrjs/askr0.0.59

How to use production readiness

Verify the locked published packages, tests, production renderer, generated routes, and deployment fallback in the same order CI uses.

  1. Import the published @askrjs/askr entrypoint.
  2. Keep production readiness configuration next to the component, route, or server composition root that owns it.
  3. Handle pending, unavailable, cancellation, and failure states, then verify the production path.
npm ci
npm run lint
npm run test
npm run build
npm run verify:static

Goal and architecture

Production hardening in Askr is mostly about wiring the hooks the server already exposes: `ServerAppOptions.probes` for health checks, `ServerAppOptions.onError` for a last-resort error handler, and `@askrjs/otel`'s `createTelemetry()` for tracing, rather than bolting on separate infrastructure. `createTelemetry()` is explicitly a bridge to whatever OpenTelemetry SDK you install — the package 'never installs an SDK, processor, backend, or exporter' — so you own the actual exporter configuration.

Implementation

Set `probes: { livez, readyz, startupz, targetz }` on `createServerApp` so your orchestrator (Kubernetes, a load balancer) can distinguish 'process is alive' from 'ready to take traffic'; each `ProbeHandler` returns a boolean, a custom `Response`, or void for a default response. Wrap request handling in `telemetry.span('askr.request', fields, work)` or use the narrower helpers (`.loader`, `.action`, `.apiOperation`, `.ssrRender`) so spans line up with Askr's own lifecycle events, and call `telemetry.extract`/`.inject` to propagate trace context across service boundaries. In front of the process, use `serve(app, { port, host, signals })` from `@askrjs/node`, which installs signal handlers for graceful shutdown by default unless you pass `signals: false`.

Failure states

An unhandled exception in a handler should hit `ServerAppOptions.onError(error, context)` and return a safe response — without it, an uncaught error can leak stack traces or internal details to the client, so treat a missing `onError` as a launch blocker, not a nice-to-have. A `readyz` probe that always returns `true` defeats the purpose — wire it to a real dependency check (database reachable, cache warm) so your orchestrator actually stops routing traffic during a bad deploy instead of load-balancing into a broken instance.

Verification

Load-test the probe endpoints themselves under contention to confirm they don't become a bottleneck or false-negative when the process is merely busy, not actually unhealthy. Kill the process mid-request in a staging environment and confirm `serve()`'s signal handling drains in-flight requests before closing, rather than dropping connections immediately. Verify a deliberately thrown error in a handler is caught by `onError` and produces the sanitized response you expect, not a stack trace.