myheats

Live heats, scoring and leaderboard for sport events
git clone https://git.in0rdr.ch/myheats.git
Log | Files | Refs | Pull requests | README | LICENSE

commit ddb856ee2efeb60577a85cde2e6640d3db2f0312
parent ac298c1e654c5fb1dbec89d842a2228abb443c3c
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date:   Sat, 28 Sep 2024 11:55:01 +0200

fix(api): MaxListenersExceededWarning, manage db sub

This MaxListenersExceededWarning warning occurred when several clients
had a watch on the scores.

MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
11 error listeners added to [Duplex]. MaxListeners is 10. Use
emitter.setMaxListeners() to increase limit at genericNodeError
(node:internal/errors:984:15)

With this fix we create the subscription on the database only once. All
client sockets are passed from the routing/server module to the db
backend and maintained as set. When the client disconnects, it is
removed from the server and the db backend set.

Diffstat:
Msrc/api/db.cjs | 27+++++++++++++++++++++++----
Msrc/api/server.cjs | 5+++--
2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/src/api/db.cjs b/src/api/db.cjs @@ -1,4 +1,6 @@ const postgres = require('postgres'); +const watchers = new Set(); +let scoreSubscription = null require('dotenv').config({ // Configure common config files and modes @@ -339,13 +341,29 @@ async function setScore(heat, athlete, judge, score) { } } -async function watchScores(clients) { +async function removeWatcher(sock) { + console.log("- Watcher removed") + watchers.delete(sock) +} + +// add client to subscription +async function watchScores(sock) { + // add client to watchlist + console.log("+ Watcher added") + watchers.add(sock); + + if (scoreSubscription !== null) { + // we are already subscribed to this publication + return scoreSubscription + } + + // subscribe to score publication try { - const { unsubscribe } = await sql.subscribe( + scoreSubscription = await sql.subscribe( '*:scores', (row, { command, relation, key, old }) => { // distributed score updates to all connected clients - for(let c of clients) { + for(let c of watchers) { c.send(JSON.stringify({ "message": "Received new scores", "data": row, @@ -357,7 +375,7 @@ async function watchScores(clients) { console.log("~ Watching scores") } ) - return unsubscribe + return scoreSubscription } catch (error) { console.error('Error occurred in watchScores:', error); throw error @@ -382,6 +400,7 @@ module.exports = { getScore, setScore, watchScores, + removeWatcher, addAthleteToHeat, addAthlete, removeAthlete, diff --git a/src/api/server.cjs b/src/api/server.cjs @@ -710,7 +710,7 @@ wss1.on('connection', function connection(sock) { console.log(' Uncle roger hears:', msg); if (msg.method === 'watchScores') { - db.watchScores(clients) + db.watchScores(sock) } } catch (error) { console.error('x Error:', error.message); @@ -723,7 +723,8 @@ wss1.on('connection', function connection(sock) { sock.on('close', function(event) { console.log(" Close event:", event.code); console.log(" Close reason:", event.reason); - clients.delete(ws); + clients.delete(sock); + db.removeWatcher(sock); }); clients.add(sock);