Observability
Structured logs
Background work logs a one-line, prefixed summary per run so a wrangler tail is readable at a glance.
The Cron handler (api/src/scheduled.ts) logs each job's outcome and swallows its errors so one bad
run never crashes the schedule:
[cron] demo generator added 3 responses
[cron] alert escalation: 2 reminded, 1 escalated, 3 emails sent
[cron] export schedules: 4 due, 4 queued
[cron] expired 7 stale partial response(s)
The queue consumer (api/src/queue.ts) logs a failure-and-retry line per bad message
([queue:<name>] message failed, retrying), and the producer (api/src/ingest.ts) logs
[ingest] enqueue failed on a transient publish failure — both keep the request path unaffected (see
Queues).
Health & readiness endpoints
The Worker exposes two probes (api/src/app.ts):
GET /health— liveness. Returns a static{ ok, service, version, time }, validated against thehealthResponsecontract.versionisSERVICE_VERSION. It constructs no providers, so it's cheap and always 200 if the Worker is up.GET /health/ready— deep readiness. Pings the database (ports.db.ping()) and returns{ ok: true, db: 'up' }on success or503{ ok: false, db: 'down' }on failure. It fails closed so a load balancer / probe pulls the instance when the DB (Hyperdrive → Neon) is unreachable, rather than serving errors.
Smoke-test both after a deploy:
curl -fsS https://<worker-domain>/health
curl -fsS https://<worker-domain>/health/ready
A 200 on /health/ready confirms the Hyperdrive binding + migrations are good; a non-200 means the
Worker is up but the DB path is misconfigured.
Error handling envelope
Unhandled errors are normalised by the Hono error handler into a consistent envelope rather than a raw stack:
- Zod validation errors →
400{ error: { code: 'validation_error', … } }. - A malformed UUID reaching a uuid column (Postgres
22P02) →404 not_found. - Anything else →
console.error('unhandled error', err)then500 internal.
The SPA's API client unwraps this envelope to surface the server's message (see SPA overview).
Sentry
The API Worker is wrapped with @sentry/cloudflare. When SENTRY_DSN is configured, Hono captures
unclassified errors and the wrapper captures exceptions escaping fetch, Queue or Cron entrypoints; with
no DSN it is a safe no-op. Default PII and performance tracing are disabled. The browser has no Sentry
SDK today, so VITE_SENTRY_DSN is reserved configuration rather than an active integration.