@@ -42,6 +42,8 @@ export class MultiTabWorkerBroker {
4242 private connections = new Map < string , { reader : MultiTabMessageReader ; writer : MultiTabMessageWriter } > ( ) ;
4343 private nextConnectionId = 0 ;
4444 private shouldDebug = false ;
45+ // Track the active lock request promise to ensure proper cleanup
46+ private activeLockPromise : Promise < any > | null = null ;
4547
4648 constructor (
4749 private readonly lockName : string ,
@@ -130,8 +132,8 @@ export class MultiTabWorkerBroker {
130132 // First, try to acquire the lock immediately with ifAvailable
131133 // This allows us to quickly determine if we can be leader or if another tab already has the lock
132134 // If we can acquire the lock, we are the leader, and we return promptly from start
133- // Note: not awaited, because this won't ever return if we do acquire the lock as the leader
134- navigator . locks
135+ // Store the lock promise so we can wait for it to complete during stop()
136+ this . activeLockPromise = navigator . locks
135137 . request ( this . lockName , { ifAvailable : true } , async ( lock ) => {
136138 if ( lock === null ) {
137139 // Lock is not available - another tab is the leader
@@ -175,8 +177,8 @@ export class MultiTabWorkerBroker {
175177 private waitForLockAndBecomeLeader ( ) : void {
176178 // Wait indefinitely to acquire the lock for failover
177179 // This will block until the current leader releases the lock
178- // Note: not awaited, because this won't ever return if we do acquire the lock and become the leader
179- navigator . locks
180+ // Store the lock promise so we can wait for it to complete during stop()
181+ this . activeLockPromise = navigator . locks
180182 . request ( this . lockName , { signal : this . lockAbortController ! . signal } , async ( ) => {
181183 // We got the lock! Become the leader and start the worker
182184 await this . becomeLeader ( ) ;
@@ -468,6 +470,21 @@ export class MultiTabWorkerBroker {
468470 this . lockAbortController . abort ( ) ;
469471 }
470472
473+ // Wait for the lock to be fully released before proceeding
474+ // This is critical to ensure a new broker can immediately acquire the same lock
475+ const lockPromiseToAwait = this . activeLockPromise ;
476+ if ( lockPromiseToAwait ) {
477+ try {
478+ await lockPromiseToAwait ;
479+ } catch ( error ) {
480+ // Ignore abort errors which are expected during stop
481+ if ( error && ( error as any ) . name !== "AbortError" ) {
482+ this . error ( "Error while waiting for lock release:" , error ) ;
483+ }
484+ }
485+ this . activeLockPromise = null ;
486+ }
487+
471488 // Terminate worker if we're the leader
472489 if ( this . worker ) {
473490 this . worker . terminate ( ) ;
0 commit comments