Skip to content

feat(concurrency): lock several aggregates in a fixed order - #75

Merged
poppycoderr merged 2 commits into
mainfrom
feat/aggregate-locks-multi
Oct 5, 2026
Merged

poppycoderr merged 2 commits into
mainfrom
feat/aggregate-locks-multi

Conversation

@poppycoderr

Copy link
Copy Markdown
Owner

Background

@AggregateLock and AggregateLocks.execute lock one aggregate. Reserving stock for an order changes one stock aggregate per order line, so it needs several locks at once. Nesting execute calls by hand acquires them in whatever order the caller passes the IDs: one order locking A then B and another locking B then A can each hold one lock and wait for the other until the wait time runs out. This came up in the inventory context of ddk-mall.

Changes

  • AggregateLocks.executeAll(type, ids, action) acquires the locks sorted by lock name, runs the action while holding all of them, and releases them in reverse order. Duplicate IDs are locked once.
  • If one lock cannot be acquired within the wait time, the locks already held are released, the action does not run, and AggregateBusyException is thrown.
operation 1: executeAll("sku", [B, A])  ─┐
operation 2: executeAll("sku", [A, B])  ─┴─►  both acquire A first, then B
                                               the loser waits on A while holding nothing

背景

@AggregateLock 和 AggregateLocks.execute 锁的是一个聚合。为订单预占库存时,每个订单行都要修改一个库存聚合,需要同时持有多把锁。自己嵌套调用 execute 时,加锁顺序取决于调用方传入标识的顺序:一个订单先锁 A 再锁 B,另一个先锁 B 再锁 A,就可能各持有一把、互相等对方那一把,直到等待超时。这个问题是在 ddk-mall 的库存上下文里遇到的。

改动

  • 新增 AggregateLocks.executeAll(type, ids, action):按锁名排序后依次加锁,持有全部锁期间执行操作,再按相反顺序释放。重复的标识只锁一次。
  • 其中一把锁在等待时间内拿不到时,已经拿到的锁会被释放,操作不执行,抛出 AggregateBusyException。

加锁顺序见上文示意。

@poppycoderr
poppycoderr merged commit 7b11fb1 into main Oct 5, 2026
4 checks passed
@poppycoderr
poppycoderr deleted the feat/aggregate-locks-multi branch October 5, 2026 02:47
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