File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -117,6 +117,30 @@ describe('withLeaderLock', () => {
117117 expect ( onFollower . mock . calls . length ) . toBeGreaterThanOrEqual ( 2 )
118118 } )
119119
120+ it ( 'follower does a final read after timeout to catch a just-finished leader' , async ( ) => {
121+ redisConfigMockFns . mockAcquireLock . mockResolvedValueOnce ( false )
122+
123+ // pollInterval=5, maxWait=9 → loop exits after 2 in-loop polls (T+5, T+10);
124+ // the third call (polls=3) is the post-deadline last-chance read.
125+ let polls = 0
126+ const onFollower = vi . fn ( async ( ) => {
127+ polls += 1
128+ if ( polls <= 2 ) return null
129+ return 'late-leader'
130+ } )
131+
132+ const result = await withLeaderLock < string > ( {
133+ key : 'k' ,
134+ pollIntervalMs : 5 ,
135+ maxWaitMs : 9 ,
136+ onLeader : async ( ) => 'should-not-run' ,
137+ onFollower,
138+ } )
139+
140+ expect ( result ) . toBe ( 'late-leader' )
141+ expect ( onFollower ) . toHaveBeenCalledTimes ( 3 )
142+ } )
143+
120144 it ( 'follower returns null after timeout' , async ( ) => {
121145 redisConfigMockFns . mockAcquireLock . mockResolvedValueOnce ( false )
122146
Original file line number Diff line number Diff line change @@ -64,6 +64,10 @@ export async function withLeaderLock<T>(opts: LeaderLockOptions<T>): Promise<T |
6464 if ( value !== null ) return value
6565 }
6666
67+ // The leader may have persisted between our final poll and now; one last check.
68+ const lastChance = await onFollower ( )
69+ if ( lastChance !== null ) return lastChance
70+
6771 logger . warn ( 'Follower timed out waiting for leader' , { key, maxWaitMs } )
6872 return null
6973}
You can’t perform that action at this time.
0 commit comments