# 数据同步机制
**本文引用的文件**
- [src/index.ts](file://src/index.ts)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts)
- [src/command/index.ts](file://src/command/index.ts)
- [src/scheduler/index.ts](file://src/scheduler/index.ts)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts)
- [wrangler.jsonc](file://wrangler.jsonc)
- [worker-configuration.d.ts](file://worker-configuration.d.ts)
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 引言
本文件系统性阐述 Cosmoe 服务端 API 的数据同步机制,覆盖以下方面:
- 实时数据获取:通过定时任务与用户交互触发的 API 调用,实现事件与预约等数据的拉取与推送。
- 增量更新:基于“最新事件 ID”的简单增量策略,仅推送新增活动。
- 批量同步:在定时任务中遍历所有已注册用户并批量发送通知。
- 冲突解决:通过 KV 存储的原子写入与幂等操作,避免重复推送与状态不一致。
- 缓存策略:KV 的 TTL 与列表接口配合,实现轻量级缓存与失效;结合业务层的“最新事件 ID”实现增量。
- 性能优化:并发控制(逐用户串行发送)、重试机制(外层调度器重试)、超时与错误恢复。
- 监控与日志:Cloudflare Worker 观测性与控制台日志;异常回滚与修复建议。
## 项目结构
该项目为 Cloudflare Workers 应用,采用模块化组织:
- 入口与调度:入口文件负责 Webhook 与计划任务;计划任务用于增量事件通知。
- 客户端封装:统一的 Cosmoe API 客户端,封装认证、查询与变更操作。
- 命令与会话:基于 grammY 的命令路由与 KV 会话存储。
- KV 命名空间:分别存储用户凭证与应用状态(如最新事件 ID)。
```mermaid
graph TB
A["入口: src/index.ts"] --> B["命令系统: src/command/index.ts"]
A --> C["计划任务: src/scheduler/index.ts"]
B --> D["客户端: src/client/cosmoe.ts"]
C --> D
B --> E["KV 会话存储
COSMOE_STORAGE"]
A --> F["KV 凭证存储
COSMOE_CREDENTIALS"]
C --> F
```
图表来源
- [src/index.ts](file://src/index.ts#L13-L46)
- [src/command/index.ts](file://src/command/index.ts#L20-L52)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
章节来源
- [src/index.ts](file://src/index.ts#L1-L47)
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)
## 核心组件
- CosmoeClient:封装认证、事件查询、个人资料、预约历史、优惠券、预约、改签、转让、取消等 API。
- 命令系统:基于 grammY 的命令与回调处理,使用 KV 适配器持久化会话。
- 计划任务:每分钟触发一次,对比“最新事件 ID”,向所有已注册用户推送新增活动。
- KV 存储:COSMOE_CREDENTIALS 存放用户凭证;COSMOE_STORAGE 存放应用状态(如 latestEventId)。
章节来源
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
- [src/command/index.ts](file://src/command/index.ts#L20-L52)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)
## 架构总览
下图展示从用户交互到服务端 API 的调用链路,以及计划任务的增量推送流程。
```mermaid
sequenceDiagram
participant U as "用户"
participant Bot as "Telegram Bot"
participant Cmd as "命令处理器"
participant KV as "KV 存储"
participant API as "Cosmoe API"
participant Sch as "计划任务"
U->>Bot : "/events" 或 "/event_"
Bot->>Cmd : 路由到对应处理器
Cmd->>API : 查询事件/详情/历史
API-->>Cmd : 返回数据
Cmd-->>U : 发送消息
U->>Bot : "/login" 进入会话
Bot->>Cmd : 进入登录对话
Cmd->>API : 获取令牌
API-->>Cmd : 返回令牌
Cmd->>KV : 写入凭证
Sch->>API : 拉取全部事件
API-->>Sch : 返回事件列表
Sch->>KV : 读取 latestEventId
Sch->>Sch : 过滤新增事件
Sch->>Bot : 向所有已注册用户发送通知
Bot-->>U : 推送新活动
Sch->>KV : 更新 latestEventId
```
图表来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L4-L26)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L60)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L74)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L4-L106)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L87)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L321)
## 详细组件分析
### CosmoeClient 数据同步策略
- 实时数据获取
- 事件列表与详情:通过 GET 请求获取,返回结构体包含事件元数据与时间槽。
- 个人资料与历史:需携带认证参数,返回用户统计与预约历史。
- 增量更新
- 计划任务通过比较“最新事件 ID”实现增量推送;若无新增则不推送。
- 批量同步
- 计划任务遍历 COSMOE_CREDENTIALS 中的所有键,向每个已注册用户发送通知。
```mermaid
flowchart TD
Start(["开始"]) --> Pull["拉取全部事件"]
Pull --> Compare["与 latestEventId 比较"]
Compare --> HasNew{"有新增事件?"}
HasNew --> |否| End(["结束"])
HasNew --> |是| Iterate["遍历所有已注册用户"]
Iterate --> Notify["逐个发送通知"]
Notify --> Update["更新 latestEventId"]
Update --> End
```
图表来源
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L87)
章节来源
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87)
### 认证与凭证管理
- 登录流程:交互式会话收集用户名与密码,调用 getToken 获取 user_id 与 token,并写入 KV。
- 凭证读取:后续命令在 KV 中读取凭证,设置到 CosmoeClient,再发起需要认证的 API 调用。
- 幂等性:KV 写入按用户 ID 键覆盖,避免重复登录导致的数据不一致。
```mermaid
sequenceDiagram
participant U as "用户"
participant Conv as "登录会话"
participant API as "Cosmoe API"
participant KV as "COSMOE_CREDENTIALS"
U->>Conv : 输入用户名/密码
Conv->>API : getToken
API-->>Conv : 返回 user_id/token
Conv->>KV : put(telegramUserId, 凭证JSON)
Conv-->>U : 登录成功
```
图表来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L13-L74)
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75)
### 事件与预约流程
- 事件列表:限制返回最近若干条,便于快速浏览。
- 事件详情:排序时间槽,生成可预约链接;根据活动日期判断是否可预约。
- 预约流程:支持优惠券选择与自动下单;失败时提示错误。
- 取消流程:二次确认键盘,确认后调用取消接口。
```mermaid
sequenceDiagram
participant U as "用户"
participant Bot as "Bot"
participant Cmd as "命令处理器"
participant API as "Cosmoe API"
U->>Bot : "/event_"
Bot->>Cmd : 解析事件ID
Cmd->>API : getEventDetail
API-->>Cmd : 返回事件详情
Cmd-->>U : 展示时间槽与预约链接
U->>Bot : "/book__"
Bot->>Cmd : 解析事件ID与槽位
Cmd->>API : getAvailableCoupons
API-->>Cmd : 返回可用优惠券
Cmd->>API : bookEvent
API-->>Cmd : 返回结果
Cmd-->>U : 成功/失败消息
```
图表来源
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L4-L60)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L118)
章节来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132)
### 计划任务与增量推送
- 触发频率:每分钟一次(cron 表达式)。
- 增量逻辑:读取 COSMOE_STORAGE 中的 latestEventId,过滤大于该值的事件,逐用户推送。
- 幂等与一致性:KV 写入保证 latestEventId 原子更新,避免重复推送。
```mermaid
flowchart TD
Tick["计划任务触发"] --> Load["读取 latestEventId"]
Load --> Fetch["获取全部事件"]
Fetch --> Filter["筛选新增事件"]
Filter --> Empty{"有新增?"}
Empty --> |否| Done["结束"]
Empty --> |是| ForEach["遍历已注册用户"]
ForEach --> Send["发送通知"]
Send --> Update["更新 latestEventId"]
Update --> Done
```
图表来源
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L87)
- [wrangler.jsonc](file://wrangler.jsonc#L13-L17)
章节来源
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [wrangler.jsonc](file://wrangler.jsonc#L13-L17)
### 冲突解决机制
- 数据一致性检查
- 计划任务在推送前比较事件 ID 与存储值,仅推送新增项,避免重复。
- 登录成功后写入 KV,后续读取凭证进行认证,减少凭据丢失风险。
- 冲突检测与解决
- KV 写入按用户键覆盖,天然具备幂等性,避免并发写入导致的覆盖问题。
- 事件推送采用“读-比对-写”的顺序,确保 latestEventId 单调递增。
- 解决方案
- 若出现重复推送,可通过重置 latestEventId 或删除重复消息进行修复。
- 对于并发写入,建议在 KV 层面增加版本号或使用带条件的写入(如 CAS)以进一步增强一致性。
章节来源
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L87)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L50-L65)
### 缓存策略
- 本地缓存
- 客户端未实现本地缓存;KV 作为应用状态与会话存储,承担轻量缓存职责。
- 缓存失效
- 计划任务通过 latestEventId 控制失效窗口;用户侧未见显式 TTL 策略。
- 缓存预热
- 无专门预热流程;可通过首次登录或访问事件详情触发数据拉取。
- 缓存更新
- 计划任务更新 latestEventId;用户侧通过 KV 会话存储维持对话状态。
章节来源
- [src/command/index.ts](file://src/command/index.ts#L20-L52)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L24-L87)
### 性能优化方案
- 并发控制
- 计划任务逐用户发送通知,避免并发风暴;可在用户维度引入队列或分批处理。
- 重试机制
- 使用 Cloudflare Worker 的计划任务重试能力;对网络抖动导致的失败进行自动重试。
- 超时与错误恢复
- API 调用应设置合理超时;对 5xx/网络错误进行指数退避重试;对 4xx 错误直接失败并记录。
- 日志与可观测性
- 启用观测性开关;在关键路径输出日志(如推送成功/失败、KV 读写错误)。
章节来源
- [wrangler.jsonc](file://wrangler.jsonc#L10-L12)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L59-L67)
## 依赖关系分析
- 组件耦合
- 命令处理器依赖 CosmoeClient 与 KV 存储;计划任务依赖 CosmoeClient 与 KV。
- KV 通过绑定名称暴露给运行时,命令系统与计划任务共享命名空间。
- 外部依赖
- Cloudflare KV、grammY、@grammyjs/conversations、@grammyjs/storage-cloudflare。
- 潜在循环依赖
- 当前结构清晰,无明显循环导入。
```mermaid
graph LR
Cmd["命令系统"] --> Client["CosmoeClient"]
Sch["计划任务"] --> Client
Cmd --> KV["KV 存储"]
Sch --> KV
Client --> API["Cosmoe API"]
```
图表来源
- [src/command/index.ts](file://src/command/index.ts#L20-L52)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L12-L21)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L140)
章节来源
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L1-L88)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L1-L503)
- [worker-configuration.d.ts](file://worker-configuration.d.ts#L1809-L1841)
## 性能考虑
- 网络调用
- 将认证与非认证接口分离,优先复用已认证实例;减少不必要的重复登录。
- KV 访问
- 合理使用 KV 的 list/get/put;避免在热路径上进行大量小对象写入。
- 速率限制
- Telegram API 对消息发送有限速,计划任务应避免在同一轮次内对同一用户多次发送。
- 资源隔离
- 将 KV 与 API 调用置于独立的执行单元,降低相互影响。
## 故障排查指南
- 登录失败
- 检查 KV 写入是否成功;确认凭证 JSON 结构与字段类型。
- 事件推送异常
- 查看 KV list 结果与发送响应;核对用户 ID 是否存在;关注控制台日志。
- 预约失败
- 核对优惠券可用性与时间槽剩余容量;查看 API 返回码与消息。
- 取消失败
- 确认用户凭证有效;检查预约状态是否允许取消。
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L67-L74)
- [src/scheduler/index.ts](file://src/scheduler/index.ts#L59-L67)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L137-L156)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L118-L124)
## 结论
Cosmoe 项目的同步机制以“KV + 计划任务 + 显式增量”为核心,实现了事件的准实时推送与用户侧的按需查询。通过 KV 的原子写入与命令系统的幂等设计,系统在无复杂分布式锁的情况下保持了基本的一致性。未来可在 KV 层引入更强的一致性保障(如 CAS)与更细粒度的缓存策略,以进一步提升可靠性与性能。
## 附录
- KV 接口要点
- 支持 get/put/list/delete;可设置 TTL 与元数据;适用于轻量级缓存与状态存储。
- 配置要点
- 计划任务 cron:每分钟触发;观测性开启;KV 命名空间绑定。
章节来源
- [worker-configuration.d.ts](file://worker-configuration.d.ts#L1809-L1841)
- [wrangler.jsonc](file://wrangler.jsonc#L10-L17)
- [wrangler.jsonc](file://wrangler.jsonc#L21-L30)