Lovable Drafts:先试出不同方案,再决定哪一版上线
Lovable 是通过对话创建网页应用的工具。Drafts 让创作者和协作者在独立预览中尝试页面、文案与布局,再把选中的方案接回项目并发布。
先尝试拆解问题、设计和实现,再展开思路,检查状态、边界与取舍,并设计验证用例。思路提供分析路径,不给出完整实现。
01
代码思考进阶
接受草稿时,如何处理并发与重复请求?
练习场景
在一个简化建站服务里,“接受草稿”表示用该草稿的完整文档替换项目主文档,不等于向网站访客发布。两位成员可能同时接受各自的草稿,同一成员也可能因超时重试。你要设计这个服务的提交协议,保住版本一致性与重试结果。baseVersion 是草稿创建时依据的主版本,expectedVersion 是客户端本次要求匹配的版本,operationId 标识同一次接受操作。
已知条件与要求
设计一个简化草稿服务的“接受”操作。这里只讨论你设计的服务,不推断 Lovable 内部实现。
- 每份草稿保存不可变 baseVersion 和候选文档;主项目有单调递增 version。接受草稿时完整替换文档,不自动合并。本题不涉及应用业务数据的增删改,也不调用外部服务;文档、版本、草稿状态和操作结果仍需按第 6 条一起保存。
- 请求包含 draftId、expectedVersion 与唯一 operationId。同一个 operationId 重试时参数必须完全相同,否则拒绝。
- 只有草稿仍为 open、baseVersion 等于 expectedVersion 且主项目 version 等于 expectedVersion 时,才允许接受。成功后整体替换主文档、版本加一、将草稿标记 accepted,并保存可重放结果。
- 两份草稿同时基于版本 7,请求同时到达时最多一个成功;另一个应得到明确冲突,不能悄悄覆盖。
- 失败提交不允许留下半更新状态;服务可能在提交成功后、响应送达前中断。客户端超时不能直接判定未接受。
- 假定存储提供事务或单个原子比较交换,可把文档、版本、草稿状态与幂等记录纳入同一原子提交;幂等结果在本题执行期间不清理。
- 给出关键状态、原子边界、重试顺序和最小反例,说明两份不同草稿的竞争与同一操作重试有何区别,不写完整实现。
用这个情境检查你的方案
A、B 都来自主版本 7。A 的接受请求已提交成功,但客户端没收到响应;此时 B 提交接受,A 又用原 operationId 重试。请说明三个响应应如何区别、主版本最后是多少,以及为什么重试 A 不是再接受一次。
需要交付什么
交付状态与存储记录图、原子提交边界、同操作重试和不同草稿竞争的序列表,以及失败窗口推演。原子表示本题列出的持久化变更要么一起完成、要么都不发生;不用提交完整服务代码。
查看思路
- 先查操作身份,再查新请求前提。 已存在 operationId 时先比对完整参数;相同则重放原结果,不再因为草稿已 accepted 而报错。不同参数必须拒绝。没有记录才进入接受流程。
- 把判断和提交放在同一原子边界。 幂等记录的查重与参数匹配也必须受同一事务、比较交换或唯一约束保护;已有结果优先于草稿状态和版本检查。对于确实没有记录的新操作,再原子地验证草稿 open、两个版本相等,再一次提交主文档、递增版本、accepted 状态和幂等结果。只在请求开头读版本、之后无条件写回,会产生覆盖。同 ID 请求竞争失败时,应重新读取胜者的完整参数与结果:参数相同就重放,参数不同则拒绝;不能把它当作一次新操作的版本冲突。
- 让并发冲突成为可解释结果。 草稿 A 和 B 都基于 7:A 提交后主版本变 8,B 检查失败,主文档保持 A。冲突后应重新取主版本并创建或调整方案;不得只把 B 的 expectedVersion 改成 8 来绕过 baseVersion 约束。
- 超时进入待确认状态。 成功提交但响应丢失时,客户端用原 operationId 和原参数重试或查询。服务重放成功结果;同一操作不会再使版本从 8 变 9。不要发送新 operationId 来猜测性补偿。
- 推演失败窗口。 提交前中断:四类状态均保持旧值;提交后响应前中断:四类状态均为新值,重试得成功;同 ID 不同参数:拒绝;A 成功后重复 B:仍不能覆盖。同 ID 同参数的 X1/X2 同时读到无记录时,X1 提交版本 8,X2 在原子边界内发现已有结果并重放,两个响应相同且版本只加一次。还应测试不存在的草稿、已拒绝草稿及版本不匹配。题设不包含多资源外部副作用,不能把这里的原子保证推广到邮件或支付。