Skip to content

fix(project): serialize concurrent project updates - #202

Open
Aether-254 wants to merge 2 commits into
linux-do:masterfrom
Aether-254:fix/serialize-concurrent-item-updates
Open

Aether-254 wants to merge 2 commits into
linux-do:masterfrom
Aether-254:fix/serialize-concurrent-item-updates

Conversation

@Aether-254

Copy link
Copy Markdown
Contributor

例行检查

  • 我已阅读并理解 贡献者公约,
  • 我已阅读并同意 贡献者许可协议 (CLA),确认我的贡献将根据项目的 MIT 许可证进行许可,
  • 我知晓如果此 PR 并不做出实质性更改,或可被认为是为了PR被合并而提交PR的,则可能不会被合并,

关联信息
无

变更内容

  • 在项目更新事务中对目标项目记录使用 SELECT ... FOR UPDATE 加行锁。
  • 在事务内重新读取最新项目状态后,再应用本次请求中的可编辑字段。
  • 保证同一项目的并发更新串行执行,避免 TotalItems 基于旧值计算产生覆盖。

变更原因

UpdateProject 原先在进入事务前加载项目数据,并在事务内通过 project.TotalItems += actualItemsCount 更新数量。

当多个请求并发更新同一项目时,它们可能读取到相同的旧 TotalItems,随后分别计算并保存,导致后提交的请求覆盖前一个请求的计数结果,使 TotalItems 与实际项目内容数量不一致。

通过在事务内重新读取并锁定项目记录,可以确保同一项目的并发更新按顺序执行,并基于最新状态计算项目数量。

@Aether-254 Aether-254 left a comment •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(resolved)

The FOR UPDATE approach fixes the lost-update problem between concurrent UpdateProject requests, but it introduces an inconsistent lock order with DeleteProject.

UpdateProject now effectively locks in this order:

projects -> project_tags -> project_items

while DeleteProject currently does:

project_tags -> project_items -> projects

This can deadlock when an update and a delete for the same project run concurrently. For example, the update can hold the project row while waiting on tag rows, while the delete holds the tag rows and later waits on the project row.

Could we make DeleteProject acquire the same project-row FOR UPDATE lock at the beginning of its transaction before touching tags/items? Ideally the receiver_id check should also be performed after acquiring that lock so the delete decision is made against the serialized state.

It would also be useful to add a concurrency regression test covering two simultaneous updates to ensure TotalItems cannot lose increments.

The serialization added here otherwise looks correct for concurrent UpdateProject calls.

@Aether-254
Aether-254 marked this pull request as draft October 7, 2026 08:40
@Aether-254
Aether-254 marked this pull request as ready for review October 7, 2026 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant