数据管理.md 16 KB

数据管理

本文引用的文件

  • src/index.ts
  • src/command/index.ts
  • src/client/cosmoe.ts
  • src/scheduler/index.ts
  • src/command/handlers/login.ts
  • src/command/handlers/history.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/cancel.ts
  • wrangler.jsonc
  • worker-configuration.d.ts

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 组件详解
  6. 依赖关系分析
  7. 性能考量
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件面向 Cosmoe Bot 的数据管理系统,聚焦于 Cloudflare KV 的配置与使用、会话状态管理、数据模型设计、数据访问模式最佳实践、迁移与备份恢复策略、性能优化以及与 Cosmoe 服务端 API 的数据同步与冲突解决策略。文档基于仓库中实际代码进行分析,帮助开发者快速理解并维护该系统。

项目结构

  • 入口与运行时:Worker 入口负责初始化 Bot、注册命令、设置 Webhook 和定时任务。
  • 命令层:通过 @grammyjs/conversations 提供交互式对话能力,使用 Cloudflare KV 作为会话存储。
  • 客户端层:封装 Cosmoe 服务端 API,统一认证、事件查询、预约、历史等接口。
  • 调度层:基于 Cron 定时任务,向已注册用户推送新活动通知,并持久化最新活动 ID。

    graph TB
    A["入口: src/index.ts"] --> B["命令注册: src/command/index.ts"]
    B --> C["会话存储: Cloudflare KV(COSMOE_STORAGE)"]
    B --> D["命令处理器<br/>login/history/bookEvent/cancel"]
    D --> E["客户端: src/client/cosmoe.ts"]
    A --> F["调度器: src/scheduler/index.ts"]
    F --> G["KV(COSMOE_STORAGE) 最新活动ID"]
    F --> H["KV(COSMOE_CREDENTIALS) 注册用户列表"]
    

图表来源

  • src/index.ts
  • src/command/index.ts
  • src/scheduler/index.ts

章节来源

  • src/index.ts
  • src/command/index.ts
  • src/scheduler/index.ts

核心组件

  • Worker 入口与环境绑定
    • 绑定 KV 命名空间:COSMOE_CREDENTIALS(用户凭证)、COSMOE_STORAGE(通用存储)。
    • 初始化 Bot 并注册命令菜单;Webhook 回调适配 Cloudflare 运行时。
  • 会话状态管理
    • 使用 @grammyjs/storage-cloudflare 将对话状态持久化到 COSMOE_STORAGE。
    • 对话读写采用 JSON 序列化/反序列化。
  • Cosmoe 客户端
    • 统一封装认证、事件、个人资料、预约、优惠券、取消等 API。
    • 支持手动设置凭证或通过交互式登录获取并保存至 COSMOE_CREDENTIALS。
  • 调度任务
    • 每分钟扫描新活动,向已注册用户发送通知,并更新最新活动 ID。

章节来源

  • src/index.ts
  • src/command/index.ts
  • src/client/cosmoe.ts
  • src/scheduler/index.ts

架构总览

下图展示从用户交互到服务端 API 与 KV 存储的整体流程。

sequenceDiagram
participant U as "用户"
participant B as "Bot(grammy)"
participant CMD as "命令处理器"
participant KV as "Cloudflare KV"
participant API as "Cosmoe API 客户端"
participant S as "Cosmoe 服务端"
U->>B : "/login" 或 "/events" 等命令
B->>CMD : 分发到对应处理器
CMD->>KV : 读取/写入会话/凭证/配置
CMD->>API : 调用认证/查询/预约/取消等接口
API->>S : 发起 HTTP 请求
S-->>API : 返回 JSON 结果
API-->>CMD : 返回业务结果
CMD-->>B : 组织消息回复
B-->>U : 发送消息/内联键盘

图表来源

  • src/command/index.ts
  • src/client/cosmoe.ts
  • src/command/handlers/login.ts
  • src/command/handlers/history.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/cancel.ts

组件详解

Cloudflare KV 配置与使用

  • 命名空间绑定
    • COSMOE_CREDENTIALS:存储用户凭证(Telegram 用户 ID -> 用户信息与令牌)。
    • COSMOE_STORAGE:存储会话状态与通用配置(如最新活动 ID)。
  • 访问模式
    • 会话存储:通过 @grammyjs/storage-cloudflare 的 KvAdapter,将对话状态以 JSON 字符串形式写入 KV。
    • 业务数据:直接使用 env.COSMOE_CREDENTIALS.get/put 与 env.COSMOE_STORAGE.get/put。
  • 序列化与反序列化
    • 会话读写:统一使用 JSON.stringify(JSON.parse(...))。
    • 凭证与配置:统一使用 JSON.stringify(JSON.parse(...))。
  • 错误处理

    • 读写异常均捕获并记录日志,避免中断对话流程。

      flowchart TD
      Start(["进入命令"]) --> GetCreds["从 KV(COSMOE_CREDENTIALS) 获取用户凭证"]
      GetCreds --> HasCreds{"是否存在凭证?"}
      HasCreds -- 否 --> PromptLogin["提示先执行 /login"]
      HasCreds -- 是 --> UseClient["初始化 CosmoeClient 并 setCredentials"]
      UseClient --> CallAPI["调用 Cosmoe API 接口"]
      CallAPI --> UpdateKV["必要时更新 KV(COSMOE_STORAGE/COSMOE_CREDENTIALS)"]
      UpdateKV --> Reply["构造并发送回复"]
      PromptLogin --> Reply
      

图表来源

  • src/command/index.ts
  • src/command/handlers/login.ts
  • src/command/handlers/history.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/cancel.ts

章节来源

  • wrangler.jsonc
  • worker-configuration.d.ts
  • src/command/index.ts
  • src/command/handlers/login.ts

会话状态管理

  • 设计原则
    • 以 Telegram 用户 ID 为键,KV 中存储对话上下文对象(JSON)。
    • 会话生命周期由 @grammyjs/conversations 控制,KV 仅作为持久化介质。
  • 创建与更新
    • 登录对话结束后,将凭证写入 COSMOE_CREDENTIALS。
    • 历史、预约、取消等命令在执行前读取凭证,确保认证有效。
  • 销毁

    • 会话结束自动清理;注销命令可结合业务逻辑删除相关 KV 条目(当前实现未显式删除,建议在 logout 中扩展)。

      sequenceDiagram
      participant U as "用户"
      participant Conv as "对话(Conversation)"
      participant KV as "KV(COSMOE_STORAGE)"
      participant Login as "登录处理器"
      U->>Conv : 触发 /login
      Conv->>Login : 进入登录对话
      Login->>KV : 写入凭证(JSON)
      KV-->>Login : 成功
      Login-->>Conv : 登录成功
      Conv-->>U : 返回结果
      

图表来源

  • src/command/index.ts
  • src/command/handlers/login.ts

章节来源

  • src/command/index.ts
  • src/command/handlers/login.ts

数据模型设计

  • 用户信息
    • 结构:包含用户标识、用户名、邮箱、角色、是否激活、创建时间等字段。
    • 存储:KV(COSMOE_CREDENTIALS) 以 Telegram 用户 ID 为键,值为包含 user_id、token、timestamp 的对象。
  • 活动数据
    • 结构:活动基本信息、描述、封面图、时间片数组等。
    • 查询:通过 CosmoeClient.getEvents/getEventDetail 获取。
  • 预约记录

    • 结构:包含预约 ID、状态、预约日期、时间段、最终价格、支付订单号、用户备注、创建时间、活动名称等。
    • 查询:通过 CosmoeClient.getMyBookings 获取。

      classDiagram
      class UserInfo {
      +number id
      +string username
      +string email
      +string user_identity
      +string role
      +number is_active
      +string created_at
      }
      class Event {
      +string id
      +string name
      +string description
      +string event_date
      +string cover_image_url
      +string description_brief
      }
      class TimeSlot {
      +string range
      +string price
      +number capacity
      +number remaining
      }
      class EventDetail {
      +number id
      +string name
      +string description
      +string event_date
      +string time_slots_with_prices
      +string cover_image_url
      +string detail_image_urls
      +number is_listed
      +number login_required
      +number allow_coupons
      +string created_at
      +TimeSlot[] slots
      +string[] gallery
      }
      class Booking {
      +number id
      +string status
      +string booking_date
      +string time_slot
      +string final_price
      +string payment_order_id
      +string notes_by_user
      +string created_at
      +string event_name
      }
      class Credentials {
      +number user_id
      +string token
      +number timestamp
      }
      EventDetail --> TimeSlot : "包含多个"
      Credentials <.. UserInfo : "关联用户"
      Booking <.. UserInfo : "关联用户"
      

图表来源

  • src/client/cosmoe.ts
  • src/command/handlers/login.ts

章节来源

  • src/client/cosmoe.ts
  • src/command/handlers/login.ts

数据访问模式最佳实践

  • 缓存策略
    • 会话状态:KV 作为持久化存储,对话结束即释放;建议为高频读取的用户资料设置 TTL(当前未使用)。
    • 通用配置:如最新活动 ID,按需读取并更新,避免频繁写入。
  • 并发控制
    • KV 写入为原子操作;对话写入通过 @grammyjs/storage-cloudflare 的 Adapter 实现,建议避免在同一会话中并发写入。
  • 事务处理
    • KV 不支持跨键事务;对于需要一致性的操作(如“先检查余量再下单”),可在应用层通过幂等设计与重试策略保证一致性。
  • 序列化与反序列化
    • 统一使用 JSON.stringify/JSON.parse;对可能为 null 的值进行判空处理,避免解析异常。

章节来源

  • src/command/index.ts
  • src/command/handlers/bookEvent.ts

数据迁移方案

  • 凭证迁移
    • 将旧 KV 中的凭证结构转换为新的 {user_id, token, timestamp} 形式;迁移后验证登录有效性。
  • 会话迁移
    • 若更换 KV 命名空间或键规则,需编写迁移脚本读取旧键,转换为新键并写入新命名空间。
  • 历史数据
    • 预约历史为只读查询,无需迁移;若需导出,可按需拉取并落库到外部存储。

章节来源

  • src/command/handlers/login.ts

备份与恢复策略

  • 备份
    • 定期导出 KV 中的关键键集(如最新活动 ID、用户凭证键列表)。
  • 恢复
    • 在新环境中重建 KV 命名空间后,导入备份数据;验证登录与会话功能正常。

章节来源

  • src/scheduler/index.ts
  • src/command/handlers/login.ts

性能优化技巧

  • 减少 KV 读写次数:合并多次写入,批量读取常用键。
  • 合理使用 TTL:对临时数据设置 TTL,降低冷数据占用。
  • 限流与退避:对外部 API 调用增加指数退避与限流,避免触发限频。
  • 消息长度控制:历史消息过长时截断,避免 Telegram API 限制。

章节来源

  • src/scheduler/index.ts
  • src/command/handlers/history.ts

与 Cosmoe 服务端 API 的数据同步与冲突解决

  • 同步机制
    • 定时任务每分钟轮询最新活动,对比本地存储的最新活动 ID,推送新增活动给已注册用户。
    • 用户侧通过命令实时查询活动与预约,保持本地状态与服务端一致。
  • 冲突解决

    • 预约冲突:在客户端层检查剩余容量与状态,避免重复提交;服务端返回错误时提示用户重试。
    • 取消与变更:通过回调确认与服务端接口完成,失败时保留本地状态并提示用户重试。

      sequenceDiagram
      participant Cron as "定时任务"
      participant KV as "KV(COSMOE_STORAGE)"
      participant API as "Cosmoe API"
      participant Users as "已注册用户"
      Cron->>KV : 读取 latestEventId
      Cron->>API : 获取所有活动
      API-->>Cron : 返回活动列表
      Cron->>KV : 更新 latestEventId(最大ID)
      loop 遍历新活动
      Cron->>Users : 发送通知
      end
      

图表来源

  • src/scheduler/index.ts

章节来源

  • src/scheduler/index.ts
  • src/client/cosmoe.ts

依赖关系分析

  • 运行时依赖
    • @grammyjs/conversations:提供对话与会话状态管理。
    • @grammyjs/storage-cloudflare:KV 适配器,用于会话持久化。
    • grammy:Telegram Bot SDK。
  • 配置依赖

    • Wrangler 将 KV 命名空间绑定到环境变量,供运行时访问。

      graph LR
      Pkg["package.json 依赖"] --> G["@grammyjs/conversations"]
      Pkg --> GC["@grammyjs/storage-cloudflare"]
      Pkg --> GM["grammy"]
      W["wrangler.jsonc"] --> KVC["COSMOE_CREDENTIALS"]
      W --> KVS["COSMOE_STORAGE"]
      

图表来源

  • package.json
  • wrangler.jsonc

章节来源

  • package.json
  • wrangler.jsonc

性能考量

  • KV 读写延迟:尽量减少不必要的 KV 操作,合并读写。
  • API 调用频率:对频繁查询的接口增加本地缓存(如活动列表),并设置合理 TTL。
  • 并发与锁:避免同一用户并发写入 KV;必要时引入分布式锁或队列。
  • 日志与可观测性:开启 Wrangler 可观测性,监控 KV 读写与 API 调用成功率。

章节来源

  • src/command/index.ts
  • src/scheduler/index.ts

故障排查指南

  • 会话读写失败
    • 检查 KV 命名空间绑定与权限;确认 JSON 解析异常(空值或格式错误)。
  • 登录失败
    • 核对用户名/密码;检查 Cosmoe API 返回码与消息;确认凭证写入 KV 成功。
  • 预约失败
    • 检查活动详情与时间片剩余容量;确认优惠券可用性;查看 API 返回错误。
  • 取消失败
    • 确认预约状态允许取消;检查回调处理逻辑与 API 返回。
  • 定时任务未推送通知
    • 检查 Cron 配置与 latestEventId 更新逻辑;确认已注册用户列表存在。

章节来源

  • src/command/index.ts
  • src/command/handlers/login.ts
  • src/command/handlers/bookEvent.ts
  • src/command/handlers/cancel.ts
  • src/scheduler/index.ts

结论

本系统通过 Cloudflare KV 实现会话状态与业务数据的持久化,结合 @grammyjs/conversations 与 Cosmoe API 客户端,提供了完整的用户交互与数据同步能力。建议在现有基础上进一步完善凭证与会话的生命周期管理、KV TTL 与缓存策略、以及对外部 API 的重试与限流机制,以提升稳定性与性能。

附录

  • KV 类型与方法参考
    • get/put/list 等方法签名与选项(如 TTL、metadata)可参考类型声明文件。
  • 部署与开发
    • 使用 Wrangler 进行本地开发与部署;配置 Cron 触发器以启用定时任务。

章节来源

  • worker-configuration.d.ts
  • wrangler.jsonc