Luigit
repositories / will

will

owned by admin

src/agent/readiness.ts

Raw
import { createServer, type Server } from 'node:http'
import { sendJson } from '../shared/http.ts'

/**
 * Pod-local readiness endpoint for the deployment platform (spec AC4):
 * readiness is local initialization only; external outages mark degraded
 * state, never readiness false.
 */

export interface ReadinessChecks {
  sessionReady: boolean
  serviceReachable: boolean
  telegramLoopReady: boolean
  storageOk: boolean
  configValid: boolean
  degraded?: string[]
}

export interface ReadinessServer {
  server: Server
  setReady(checks: ReadinessChecks): void
  close(): Promise<void>
}

export function isReady(checks: ReadinessChecks): boolean {
  return checks.sessionReady && checks.serviceReachable && checks.configValid
}

export function startReadinessServer(addr: string): Promise<ReadinessServer> {
  let current: ReadinessChecks = {
    sessionReady: false,
    serviceReachable: false,
    telegramLoopReady: false,
    storageOk: true,
    configValid: true,
  }
  const server = createServer((req, res) => {
    const url = new URL(req.url ?? '/', 'http://localhost')
    if (url.pathname === '/readyz' || url.pathname === '/healthz') {
      sendJson(res, isReady(current) ? 200 : 503, { ready: isReady(current), checks: current })
      return
    }
    sendJson(res, 404, { error: 'not found' })
  })
  return new Promise((resolve, reject) => {
    const [host, port] = addr.split(':')
    server.once('error', reject)
    server.listen(Number(port), host, () => {
      resolve({
        server,
        setReady(checks) {
          current = checks
        },
        close: () => new Promise<void>((res) => server.close(() => res())),
      })
    })
  })
}