← 中文资源

简体中文版本

构建本地优先的笔记同步服务

一个本地优先笔记的完整同步服务:版本向量、冲突检测、合并策略、增量同步与分叉测试。

阅读英文原文

项目概述

本项目实现本地优先的笔记同步服务:在设备离线编辑后检测同一笔记的并发修改,并用确定性规则合并而非静默覆盖。冲突被显式上报而非隐藏,因为悄悄选一个赢家会丢掉用户的文字。

架构与关键决策

每条笔记携带版本向量与更新时间,改动以带 id 的仅追加日志记录;拉取返回游标之后的条目,使设备只收到未见过的内容。推送声明其编辑所基于的版本,若服务端已前进则该次编辑为并发,检测为冲突而非盲改。冲突以确定性规则(如三方合并)解决,使每个设备对同一输入得到相同字节。游标是日志中的单调位置,断线后可续传,重试按改动 id 去重。

实施与测试

在两台模拟设备上离线编辑同一条笔记,同步双方,断言报告冲突且合并结果一致;断言拉取只返回游标之后的内容;断言重复的改动 id 只产生一条记录;断言基于过期版本的推送被判为冲突。

限制与后续

  • 合并面向文本,字段级结构化合并仅近似实现。
  • 日志按周期快照压缩,陈旧游标可能需全量重同步。
  • 无服务端冲突界面,用户体验取决于客户端。

代码示例

pnpm init
pnpm add pg express
pnpm add -D typescript tsx vitest
notes-sync/
├── src/pull.ts
├── src/push.ts
├── src/conflict.ts
├── src/cursor.ts
├── tests/sync.test.ts
└── package.json
const vv = { [deviceId]: previous[deviceId] + 1 };
SELECT * FROM changes WHERE seq > $1 ORDER BY seq LIMIT 500;
if (base.equals(server.version)) return apply(change); return conflict(change);
const merged = deterministicMerge(local, remote);
await db.setCursor(clientId, lastSeq);
pnpm vitest run