airi/apps/server/docs/ai-context/workers-and-runtime.md
RainbowBird f259e7eb92
Some checks are pending
Cloudflare Workers (server-dev) / Deploy - stage-web (server-dev) (push) Waiting to run
feat(server): replace legacy health endpoints with K8s-style /livez and /readyz probes
2026-05-15 19:02:57 +08:00

3.6 KiB
Raw Permalink Blame History

Workers And Runtime

进程角色

入口:src/bin/run.ts

  • api
    • 启动 Hono HTTP + WebSocket 服务
    • 没有任何"常驻后台 loop",也没有"POST 触发的 fire-and-forget"。所有写路径都在请求线程里同步完成

不再有独立的 worker / billing-consumer 进程。原先的 Redis Stream billing event 链路、advisory-lock poller、admin flux grant batch 异步处理全部移除。

API 角色

启动路径:

  • src/bin/run.ts
  • runApiServer()
  • createApp()

启动时会做的事情:

  • 解析 env
  • 初始化日志
  • 可选初始化 OTel
  • 连接 Postgres / Redis
  • 跑数据库迁移
  • 装配服务
  • 启动 HTTP server
  • 注入 WebSocket

Admin flux grant同步执行

详见 admin-flux-grants.md。简要admin 调 POST /api/admin/flux-grants,路由 handler 在请求线程内顺序对每个 recipient 调 BillingService.creditFluxHTTP 响应里直接返回每条的 outcomegranted / skipped / failed。失败由 admin 看响应自行重发,可选 idempotencyKey 让重发安全。

失败 / 崩溃恢复

服务端没有需要恢复的"中间状态"。每次 creditFlux 自己是一个 DB 事务;要么写进 flux_transaction ledger 要么没写,没有第三态。(user_id, request_id) partial unique index 保证带 idempotencyKey 的重发不会双发。

环境变量分层

基础运行

  • HOST
  • PORT
  • API_SERVER_URL
  • DATABASE_URL
  • REDIS_URL

Auth

  • AUTH_GOOGLE_CLIENT_ID
  • AUTH_GOOGLE_CLIENT_SECRET
  • AUTH_GITHUB_CLIENT_ID
  • AUTH_GITHUB_CLIENT_SECRET

Stripe

  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET

OTel

  • OTEL_SERVICE_NAMESPACE
  • OTEL_SERVICE_NAME
  • OTEL_TRACES_SAMPLING_RATIO
  • OTEL_EXPORTER_OTLP_ENDPOINT
  • OTEL_EXPORTER_OTLP_HEADERS
  • OTEL_DEBUG

NOTICE: BILLING_EVENTS_* 已全部移除。

聊天 WebSocket 运行时

src/routes/chat-ws/index.ts 是另一种独立运行时:

  • 同实例连接保存在进程内 Map
  • 跨实例 fan-out 通过 Redis Pub/Sub

这意味着:

  • WS 广播不具备持久化和重放能力
  • 真正补齐消息还是靠 pullMessages
  • 广播只是为了降低拉取延迟,不代表存在旧式 sync 端点

如果要改 Redis key / channel 构造、Pub/Sub payload先看 redis-boundaries-and-pubsub.md

OpenTelemetry

初始化在 instrumentation.tsNodeSDK lifecycle+ src/otel/index.tsmetric handles+ src/otel/gauges/*.tsDB-backed ObservableGauge callbacks例如 gauges/active-sessions.ts)。

启用条件:

  • OTEL_EXPORTER_OTLP_ENDPOINT 存在

覆盖面:

  • HTTP
  • Auth
  • Chat engagement
  • Revenue
  • LLM
  • DB / Redis instrumentation

重要实现细节:

  • sdk.start() 必须发生在 metrics.getMeter() 之前
  • /livez/readyz 会被 HTTP instrumentation 忽略

运行时修改建议

  • 新增异步工作:先问三遍"为什么不能在请求线程里同步做完"。绝大多数 admin / webhook / 短 batch 都可以;实在不行也优先 fire-and-forget per-request而不是引入常驻 loop。
  • 真的需要 idle-driven 的活(清理过期 token、定时聚合等先评估是否值得。如果是开 Postgres pg_cron 或外部 cron service 调专门的 internal API endpoint比"进程内常驻 loop"更可观察、更易停。
  • 改 Stripe / Flux 写路径:看 billing-architecture.md,所有 ledger 写入都在事务内同步完成
  • 改聊天同步:先区分"持久化消息"与"广播通知"两层
  • 改部署限流:注意当前 rate-limit.ts 仍是单实例内存模型