Files
moeka-project/apps/server/docs/ai-context/workers-and-runtime.md
T

162 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Workers And Runtime
## 进程角色
统一入口在 `src/bin/run.ts`
- `api`
- 启动 Hono HTTP + WebSocket 服务
- `billing-consumer`
- 消费 Redis Stream `billing-events`,异步将 ledger、audit log、LLM 请求日志写入 DB
这两个角色是当前服务端部署拆分的基本单位。
## API 角色
启动路径:
- `src/bin/run.ts`
- `runApiServer()`
- `createApp()`
启动时会做的事情:
- 解析 env
- 初始化日志
- 可选初始化 OTel
- 连接 Postgres / Redis
- 跑数据库迁移
- 装配服务
- 启动 HTTP server
- 注入 WebSocket
## Billing Consumer
实现位置:
- 入口:`src/bin/run-billing-consumer.ts`
- worker`src/services/billing-mq-worker.ts`
- stream adapter`src/services/billing-mq.ts`
工作流程:
1. 以 consumer group 模式消费 Redis Stream `billing-events`
2. 根据事件类型分发处理:
- `flux.debited` — 写 `flux_ledger``flux_audit_log`
- `llm.request.log` — 写 `llm_request_log`
3. 处理成功后 ACK;handler 抛错时不 ACK,消息保持 pending 等待重试
相关环境变量:
- `BILLING_EVENTS_STREAM`
- `BILLING_EVENTS_CONSUMER_NAME`
- `BILLING_EVENTS_BATCH_SIZE`
- `BILLING_EVENTS_BLOCK_MS`
- `BILLING_EVENTS_MIN_IDLE_MS`
## Redis Streams 语义
`billing-mq.ts` 把 Redis Streams 抽象成:
- `publish()`
- `ensureConsumerGroup()`
- `consume()`
- `claimIdleMessages()`
- `ack()`
这层约束了消息处理语义:
- 使用 consumer group
- 使用 pending reclaim
- handler 抛错时不 ack,消息保持 pending
因此新增新的 stream consumer 时,最安全的方式通常是复用这层,不要自己裸写 `XREADGROUP`
## 聊天 WebSocket 运行时
`src/routes/chat-ws.ts` 还有一套独立于 Redis Streams 的运行时机制:
- 同实例连接保存在进程内 `Map`
- 跨实例 fan-out 通过 Redis Pub/Sub
这意味着:
- WS 广播不具备持久化和重放能力
- 真正补齐消息还是靠 `pullMessages`
- 广播只是为了降低拉取延迟,不代表存在旧式 `sync` 端点
## OpenTelemetry
初始化在 `src/libs/otel.ts`
启用条件:
- `OTEL_EXPORTER_OTLP_ENDPOINT` 存在
覆盖面:
- HTTP
- Auth
- Chat engagement
- Revenue
- LLM
- DB / Redis instrumentation
重要实现细节:
- `sdk.start()` 必须发生在 `metrics.getMeter()` 之前
- `/health` 会被 HTTP instrumentation 忽略
## 环境变量分层
### 基础运行
- `HOST`
- `PORT`
- `API_SERVER_URL`
- `CLIENT_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`
### Billing MQ
- `BILLING_EVENTS_STREAM`
- `BILLING_EVENTS_CONSUMER_NAME`
- `BILLING_EVENTS_BATCH_SIZE`
- `BILLING_EVENTS_BLOCK_MS`
- `BILLING_EVENTS_MIN_IDLE_MS`
### OTel
- `OTEL_SERVICE_NAMESPACE`
- `OTEL_SERVICE_NAME`
- `OTEL_TRACES_SAMPLING_RATIO`
- `OTEL_EXPORTER_OTLP_ENDPOINT`
- `OTEL_EXPORTER_OTLP_HEADERS`
- `OTEL_DEBUG`
## 运行时修改建议
如果你要改:
- 新增 worker
- 先看 `run.ts` 的角色模型和 `billing-mq-worker.ts`
- 改事件分发
- 先看 billing-consumer handler,在 `billing-mq-worker.ts` 中增加新的事件处理分支
- 改聊天同步
- 先区分“持久化消息”与“广播通知”两层
- 改部署限流
- 注意当前 `rate-limit.ts` 仍是单实例内存模型