Avoid lock inversion in raft mock transport - #8532
Conversation
Deliver mock transport callbacks after releasing the hub lock to prevent deadlocks with Raft node locks. This deflakes TestNRGLeaderWithoutQuorumAfterPeerAdd. Signed-off-by: Daniele Sciascia <daniele@nats.io>
|
@claude review |
|
Claude finished @sciascid's task in 2m 13s —— View job Code Review
Summary: The fix is correct and well-targeted. It resolves a classic lock-inversion deadlock where What the fix doesThe original // Before — deadlock-prone
h.mu.Lock()
for id, transport := range h.transports {
res := transport.sub.Match(subject)
for _, sub := range res.psubs {
sub.icb(sub, nil, transport.acc, subject, reply, msg) // under hub lock!
}
}
h.mu.Unlock()The fix splits this into two phases — collect while locked, deliver after unlocking — which is the standard remedy for this pattern: // After — lock-inversion free
h.mu.Lock()
for id, transport := range h.transports {
result := transport.sub.Match(subject)
subscriptions = append(subscriptions, result.psubs...)
}
h.mu.Unlock()
for _, sub := range subscriptions {
sub.icb(sub, nil, nil, subject, reply, msg)
}Correctness
Passing Subscription lifetime:
Concurrent publishes: The original code serialized all
One minor observationThe comment above
This remains true since the call chain is: VerdictThe fix is correct, minimal, and addresses the root cause cleanly. No concerns. |
Deliver mock transport callbacks after releasing the hub lock to prevent deadlocks with Raft node locks. This deflakes TestNRGLeaderWithoutQuorumAfterPeerAdd.