Skip to content

Commit 3009abc

Browse files
authored
FIX unhandled rejections (#1384)
* FIX unhandled rejections * ADD changelog * FIX lint
1 parent 00f3a1d commit 3009abc

5 files changed

Lines changed: 64 additions & 5 deletions

File tree

.github/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ const elector = createLeaderElection(channel);
257257
await elector.die();
258258
```
259259

260+
**NOTICE:** When the leader dies, its calls to `awaitLeadership()` will no longer resolve.
261+
260262
### Handle duplicate leaders
261263

262264
Duplicate leadership can happen on rare occurences like when the [CPU is on 100%](https://web.archive.org/web/20201221051328/https://github.com/pubkey/broadcast-channel/issues/385) for longer time, or the browser [has throttled the javascript timers](https://web.archive.org/web/20201221051312/https://github.com/pubkey/broadcast-channel/issues/414).

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ jobs:
9898
runs-on: ubuntu-22.04
9999
strategy:
100100
matrix:
101-
node: ['18.18.2', '20.9.0']
101+
node: ['22.22.0', '24.13.0']
102102
steps:
103103
- uses: actions/checkout@v6
104104
- name: Setup Node.js environment

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
## X.X.X (comming soon)
55

6+
## 7.3.0 (20 January 2026)
7+
8+
- FIX `unhandledRejection` thrown when `leader.die()` is called while a call to `awaitLeadership()` is still running.
9+
10+
611
## 7.2.0 (27 October 2025)
712

813
- fix(leader-election-web-lock): rethrow WebLocks acquisition errors to avoid stuck leader election [#1360](https://github.com/pubkey/broadcast-channel/pull/1360)

src/leader-election-web-lock.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const LeaderElectionWebLock = function (broadcastChannel, options) {
3131
};
3232

3333

34+
const LEADER_DIE_ABORT_SIGNAL_MESSAGE = 'LeaderElectionWebLock.die() called';
3435

3536
LeaderElectionWebLock.prototype = {
3637
hasLeader() {
@@ -65,10 +66,19 @@ LeaderElectionWebLock.prototype = {
6566
return returnPromise;
6667
}
6768
).catch((err) => {
68-
if (this._wKMC.rej) {
69-
this._wKMC.rej(err);
69+
if (err.message && err.message === LEADER_DIE_ABORT_SIGNAL_MESSAGE) {
70+
/**
71+
* In this case we do nothing!
72+
* The leader died and awaitLeadership()
73+
* will never resolve. Also since this is not an error,
74+
* it will not throw.
75+
*/
76+
} else {
77+
if (this._wKMC.rej) {
78+
this._wKMC.rej(err);
79+
}
80+
reject(err);
7081
}
71-
reject(err);
7282
});
7383
});
7484
}
@@ -90,8 +100,13 @@ LeaderElectionWebLock.prototype = {
90100
if (this._wKMC.res) {
91101
this._wKMC.res();
92102
}
103+
104+
/**
105+
* We have to fire an abort signal
106+
* so that the navigator.locks.request stops.
107+
*/
93108
if (this._wKMC.c) {
94-
this._wKMC.c.abort(new Error('LeaderElectionWebLock.die() called'));
109+
this._wKMC.c.abort(new Error(LEADER_DIE_ABORT_SIGNAL_MESSAGE));
95110
}
96111
return sendLeaderMessage(this, 'death');
97112
}

test/integration.test.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@ if (isNode) {
1818
console.dir(origin);
1919
process.exit(1);
2020
});
21+
22+
/**
23+
* In no case it should throw an unhandledRejection
24+
*/
25+
process.on('unhandledRejection', async function (error, p) {
26+
console.log('unhandledRejection');
27+
28+
// use log and error because some CI terminals do not show errors.
29+
try {
30+
console.dir(await p);
31+
} catch (err) {
32+
console.log('------- COULD NOT AWAIT p');
33+
logUnknownError(err);
34+
logUnknownError(error);
35+
process.exit(5);
36+
}
37+
console.dir((error).stack);
38+
console.error(error);
39+
console.dir(error);
40+
console.log('------- END OF unhandledRejection debug logs');
41+
process.exit(5);
42+
});
2143
}
2244

2345
/**
@@ -797,3 +819,18 @@ if (isNode) {
797819
}
798820

799821
useOptions.forEach(o => runTest(o));
822+
823+
824+
function logUnknownError(err) {
825+
if (err instanceof Error) {
826+
console.error(err.stack || err.message);
827+
} else {
828+
console.error('Non-Error rejection:', err);
829+
console.error(err.stack || err.message);
830+
try {
831+
console.error(JSON.stringify(err, null, 2));
832+
} catch (err2) {
833+
console.error(String(err));
834+
}
835+
}
836+
}

0 commit comments

Comments
 (0)