ArkTS 端云一体待办清单:8 个云函数撑起多端同步的工程细节

举报
yd_284028467 发表于 2026/11/08 10:45:46 2026/11/08
【摘要】 从 ArkTS 端侧到 FunctionGraph + APIG + RDS 的端云一体待办清单实践:三张表设计、会话鉴权边界、30 秒增量轮询与版本号冲突处理、8 个云函数的拆分依据,以及冷启动与连接池的踩坑记录。

端云一体最容易被低估的地方不是写页面,而是把「一条待办从点击到落库再到另一台设备看见」这条链路做扎实。这篇记录我在鸿蒙开发实践中心完成「云同步待办清单」案例时的架构选择与工程细节:ArkTS 端侧、Serverless 云侧、8 个 FunctionGraph 云函数、APIG 专享版与 RDS MySQL 三张表。

一、为什么端侧不直连数据库

鸿蒙端侧直连 MySQL 在演示阶段很爽,但放到真实网络里有两个硬伤:数据库账号随安装包分发等于公开凭据;移动网络下的长连接质量不可控,重连逻辑会吃掉大量业务代码。把数据访问收口到云函数,端侧只面对一个 HTTP 接口层,是更稳的边界。

这样做还有个副作用收益:函数层天然是同步策略的落点。端侧只负责发起意图,服务端负责保证状态一致,冲突处理逻辑不必在每台设备上重复实现一遍。

二、整体架构

  • 端侧:ArkTS + ArkUI,页面层只调 ApiClient,不感知云函数名称。
  • 接入层:APIG 专享版,统一做鉴权校验、限流与 CORS。
  • 计算层:8 个 FunctionGraph 云函数,按领域拆分而非按接口拆分。
  • 存储层:RDS MySQL,users / sessions / tasks 三张表。
  • 部署:deploy.sh 一键下发函数与 APIG 路由,verify_api.sh 做端到端验收。

把 APIG 放在函数前面是刻意选择:函数本身不做鉴权中间件,鉴权交给网关,函数只相信网关注入的 userId。这样函数的单元测试不需要伪造 token,测试成本明显下降。

三、三张表的数据模型

表结构尽量窄,把可变部分放在 JSON 字段里,但索引字段必须显式建列:

CREATE TABLE tasks (
  id          BIGINT PRIMARY KEY AUTO_INCREMENT,
  user_id     VARCHAR(32)  NOT NULL,
  title       VARCHAR(200) NOT NULL,
  done        TINYINT(1)   NOT NULL DEFAULT 0,
  priority    TINYINT      NOT NULL DEFAULT 1,
  due_at      DATETIME     NULL,
  version     INT          NOT NULL DEFAULT 1,
  updated_at  DATETIME     NOT NULL,
  deleted     TINYINT(1)   NOT NULL DEFAULT 0,
  KEY idx_user_updated (user_id, updated_at)
) DEFAULT CHARSET = utf8mb4;

idx_user_updated 是同步查询的命脉。端侧轮询只问「我这个用户在某个时间点之后有哪些变更」,没有这个联合索引,数据量一上来就会退化成全表扫描。deleted 用软删除而不是物理删除,否则增量同步拿不到删除事件,另一台设备会永远留着那条记录。

四、会话与鉴权

sessions 表只做一件事:把登录态映射成短期凭证。函数侧不存内存态,鉴权完全靠网关验签后的 userId 透传,因此任何一个函数实例被回收都不影响在线用户。

这里有个容易踩的坑:时间字段统一用 UTC 存储,端侧展示时再转本地时区。一开始我在函数里用了服务器本地时间写 updated_at,跨时区测试时同步顺序直接乱掉,表现为「老数据覆盖新数据」。

五、同步策略:轮询 + 乐观更新 + 版本号

端侧每 30 秒拉一次增量,写操作先改本地再发请求,失败回滚。冲突用单调递增的 version 解决:更新语句带上 version 条件,影响行数为 0 说明服务端已被别人改过,函数返回 409,端侧重新拉取该条目。

// 云函数 updateTask 的核心更新语句
const [rows] = await pool.execute(
  'UPDATE tasks SET title=?, done=?, priority=?, due_at=?, version=version+1, updated_at=UTC_TIMESTAMP() ' +
  'WHERE id=? AND user_id=? AND version=? AND deleted=0',
  [title, done, priority, dueAt, id, userId, clientVersion]
);
if (rows.affectedRows === 0) return { code: 409, msg: 'version conflict' };

端侧的乐观更新必须配一条「回滚快照」,否则 409 之后用户看到的是自己刚输入的标题凭空消失。我的做法是每次写操作前把该项的旧对象压栈,失败时整对象还原,而不是逐字段回退。

六、8 个云函数的边界划分

  • login / logout:会话建立与撤销,只碰 sessions 表。
  • listTasks:增量拉取,只读,走 idx_user_updated。
  • createTask / updateTask / deleteTask:写路径,全部带 version 校验。
  • batchSync:端侧离线期间积压的多次写操作一次性提交,按客户端时间戳排序。
  • profile:用户信息聚合,被多个页面复用。

按领域拆分而不是按 REST 动词拆成二十个函数,好处是冷启动次数可控,也避免函数之间互相调用形成链式超时。batchSync 是后来补的:端侧在地铁里断网十几分钟,逐条重放会产生大量 409,合并成一次提交后冲突率明显下降。

七、把验收脚本化

verify_api.sh 里串了一条完整的业务链路:注册 → 登录 → 建任务 → 改任务 → 制造版本冲突 → 增量拉取断言 → 软删除 → 再次拉取断言为空。案例文档里写「一键部署、端到端验收」,实际价值主要在这个脚本上——它把「接口能通」变成了「语义正确」。

#!/usr/bin/env bash
set -euo pipefail
TOKEN=$(curl -s -X POST "$API/login" -d '{"account":"demo","pwd":"demo"}' | jq -r .token)
TID=$(curl -s -X POST "$API/tasks" -H "Authorization: Bearer $TOKEN" \
      -d '{"title":"写周报","priority":2}' | jq -r .id)
curl -sf -X PATCH "$API/tasks/$TID" -H "Authorization: Bearer $TOKEN" \
     -d '{"title":"写周报v2","version":1}' > /dev/null
# 用过期 version 制造冲突,必须返回 409
CODE=$(curl -s -o /dev/null -w '%{http_code}' -X PATCH "$API/tasks/$TID" \
       -H "Authorization: Bearer $TOKEN" -d '{"title":"x","version":1}')
[ "$CODE" = "409" ] || { echo "conflict check failed: $CODE"; exit 1; }
echo "verify ok" 

八、几个真实的坑

  • 冷启动:函数首次调用 500ms 以上很常见,端侧首屏必须有骨架屏,不能假设 200ms 返回。
  • 连接池:函数实例会被并发复用,pool 的连接上限要小于 RDS 最大连接数除以最大并发实例数,否则高峰期直接报 too many connections。
  • ArkTS 严格类型:接口返回用 interface 描述并做了一层运行时校验,后端加字段不会崩,但字段改名会立即暴露,比隐式 any 安全得多。
  • 轮询与页面生命周期的耦合:页面切到后台要停轮询,回到前台立即拉一次全量对齐,只做增量会出现「回来以后数据是旧的」这种错觉。

九、小结

这个案例的代码量不大,难的是把边界划清楚:端侧只管意图与展示,网关管鉴权,函数管语义与一致性,表结构管查询效率。把这四层各自的责任固定下来之后,加功能就变成在既定位置上填空,而不是每次重新讨论「这段逻辑该放哪儿」。

如果要在生产里继续往前走,下一步我会把 30 秒轮询换成长连接推送,并给 batchSync 加上幂等键——这两件事才是待办类应用真正变成「多端一致」的分水岭。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。