diff --git a/server/model/Game.js b/server/model/Game.js index a772f27..58d70a1 100644 --- a/server/model/Game.js +++ b/server/model/Game.js @@ -19,6 +19,7 @@ class Game { this.hasTimer = hasTimer; this.hasDedicatedModerator = hasDedicatedModerator; this.originalModeratorId = originalModeratorId; + this.createTime = createTime; this.timerParams = timerParams; this.isFull = false; this.timeRemaining = null; diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js index 18c425a..8cec665 100644 --- a/server/modules/GameManager.js +++ b/server/modules/GameManager.js @@ -25,8 +25,7 @@ class GameManager { this.logger.error('Tried to create game with invalid options: ' + JSON.stringify(gameParams)); return Promise.reject(globals.ERROR_MESSAGE.BAD_CREATE_REQUEST); } else { - // to avoid excessive memory build-up, every time a game is created, check for and purge any stale games. - // pruneStaleGames(this.activeGameRunner.activeGames, this.activeGameRunner.timerThreads, this.logger); + this.pruneStaleGames(); const newAccessCode = this.generateAccessCode(globals.ACCESS_CODE_CHAR_POOL); if (newAccessCode === null) { return Promise.reject(globals.ERROR_MESSAGE.NO_UNIQUE_ACCESS_CODE); @@ -382,6 +381,23 @@ class GameManager { return array; }; + + pruneStaleGames = () => { + this.activeGameRunner.activeGames.forEach((value, key) => { + if (value.createTime) { + const createDate = new Date(value.createTime); + if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) { + this.logger.info('PRUNING STALE GAME ' + key); + this.activeGameRunner.activeGames.delete(key); + if (this.activeGameRunner.timerThreads[key]) { + this.logger.info('KILLING STALE TIMER PROCESS FOR ' + key); + this.activeGameRunner.timerThreads[key].kill(); + delete this.activeGameRunner.timerThreads[key]; + } + } + } + }); + }; } function getRandomInt (max) { @@ -478,23 +494,6 @@ function isNameTaken (game, name) { || (game.spectators.find((spectator) => spectator.name.toLowerCase().trim() === processedName)); } -// function pruneStaleGames (activeGames, timerThreads, logger) { -// for (const [accessCode, game] of Object.entries(activeGames)) { -// if (game.createTime) { -// const createDate = new Date(game.createTime); -// if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) { -// logger.info('PRUNING STALE GAME ' + accessCode); -// delete activeGames[accessCode]; -// if (timerThreads[accessCode]) { -// logger.info('KILLING STALE TIMER PROCESS FOR ' + accessCode); -// timerThreads[accessCode].kill(); -// delete timerThreads[accessCode]; -// } -// } -// } -// } -// } - function getGameSize (cards) { let quantity = 0; for (const card of cards) { diff --git a/spec/unit/server/modules/GameManager_Spec.js b/spec/unit/server/modules/GameManager_Spec.js index 58af434..5be4d16 100644 --- a/spec/unit/server/modules/GameManager_Spec.js +++ b/spec/unit/server/modules/GameManager_Spec.js @@ -432,4 +432,27 @@ describe('GameManager', () => { expect(emitSpy).toHaveBeenCalledWith(globals.EVENT_IDS.START_GAME); }); }); + + describe('#pruneStaleGames', () => { + it('delete a game if it was created more than 24 hours ago', () => { + const moreThan24HoursAgo = new Date(); + moreThan24HoursAgo.setDate(moreThan24HoursAgo.getDate() - 1); + moreThan24HoursAgo.setHours(moreThan24HoursAgo.getHours() - 1); + gameManager.activeGameRunner.activeGames = new Map([['AAAA', { createTime: moreThan24HoursAgo.toJSON() }]]); + + gameManager.pruneStaleGames(); + + expect(gameManager.activeGameRunner.activeGames.size).toEqual(0); + }); + + it('should not delete a game if it was not created more than 24 hours ago', () => { + const lessThan24HoursAgo = new Date(); + lessThan24HoursAgo.setHours(lessThan24HoursAgo.getHours() - 23); + gameManager.activeGameRunner.activeGames = new Map([['AAAA', { createTime: lessThan24HoursAgo.toJSON() }]]); + + gameManager.pruneStaleGames(); + + expect(gameManager.activeGameRunner.activeGames.size).toEqual(1); + }); + }); });