From 80eb1ac6524ca48243666e564a8187292bfe12bb Mon Sep 17 00:00:00 2001 From: Dieter Reinert Date: Mon, 6 Jan 2025 12:10:35 +0100 Subject: [PATCH 1/5] Replays: Implement retry mechanism for database operations Add retry logic to handle transient database errors in the Replays module. This update introduces a retry mechanism for database insert operations within the `Replays` class to enhance stability and prevent crashes caused by transient issues such as network interruptions or temporary database unavailability. By implementing this retry logic, the system can recover from intermittent errors without requiring manual intervention. --- server/replays.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/server/replays.ts b/server/replays.ts index 82e2b8b73a6a..51003157379c 100644 --- a/server/replays.ts +++ b/server/replays.ts @@ -91,11 +91,28 @@ export const Replays = new class { return replayData; } + export async function retry(fn: () => Promise, retries: number = 3, delayMs: number = 1000): Promise { + let lastError: any; + for (let attempt = 1; attempt <= retries; attempt++) { + try { + return await fn(); + } catch (error) { + lastError = error; + if (attempt < retries) { + console.warn(`Attempt ${attempt} failed. Retrying in ${delayMs}ms...`); + await new Promise(res => setTimeout(res, delayMs)); + } + } + } + throw lastError; + } + async add(replay: Replay) { // obviously upsert exists but this is the easiest way when multiple things need to be changed const replayData = this.toReplayRow(replay); try { - await replays.insert(replayData); + // Retry the insert operation up to 3 times with a 1-second delay between attempts + await retry(() => replays.insert(replayData), 3, 1000); for (const playerName of replay.players) { await replayPlayers.insert({ playerid: toID(playerName), From 9fab2c602bbb9b3025372ca98ee18d564d555b03 Mon Sep 17 00:00:00 2001 From: Dieter Reinert Date: Mon, 6 Jan 2025 12:11:42 +0100 Subject: [PATCH 2/5] Remove: redundant code --- server/replays.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/replays.ts b/server/replays.ts index 51003157379c..200e9096d4b2 100644 --- a/server/replays.ts +++ b/server/replays.ts @@ -91,7 +91,7 @@ export const Replays = new class { return replayData; } - export async function retry(fn: () => Promise, retries: number = 3, delayMs: number = 1000): Promise { + async retry(fn: () => Promise, retries: number = 3, delayMs: number = 1000): Promise { let lastError: any; for (let attempt = 1; attempt <= retries; attempt++) { try { From e64e2a512e8bb9937efd386f4ae1e8983bdb3215 Mon Sep 17 00:00:00 2001 From: Dieter Reinert Date: Mon, 6 Jan 2025 12:12:18 +0100 Subject: [PATCH 3/5] Remove: console.log --- server/replays.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/replays.ts b/server/replays.ts index 200e9096d4b2..8752eeccf0f5 100644 --- a/server/replays.ts +++ b/server/replays.ts @@ -99,7 +99,6 @@ export const Replays = new class { } catch (error) { lastError = error; if (attempt < retries) { - console.warn(`Attempt ${attempt} failed. Retrying in ${delayMs}ms...`); await new Promise(res => setTimeout(res, delayMs)); } } From d97353b9afb481c29b47bde348a4fed5be3e50e8 Mon Sep 17 00:00:00 2001 From: Dieter Reinert Date: Mon, 6 Jan 2025 13:00:07 +0100 Subject: [PATCH 4/5] fix: @typescript-eslint/no-inferrable-types --- server/replays.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/replays.ts b/server/replays.ts index 8752eeccf0f5..8be91e4a6202 100644 --- a/server/replays.ts +++ b/server/replays.ts @@ -91,7 +91,7 @@ export const Replays = new class { return replayData; } - async retry(fn: () => Promise, retries: number = 3, delayMs: number = 1000): Promise { + async retry(fn: () => Promise, retries = 3, delayMs = 1000): Promise { let lastError: any; for (let attempt = 1; attempt <= retries; attempt++) { try { From e48a52328aa859ff9df5b3ea718a01710c49ed59 Mon Sep 17 00:00:00 2001 From: Dieter Reinert Date: Mon, 6 Jan 2025 13:08:13 +0100 Subject: [PATCH 5/5] fix: use this --- server/replays.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/replays.ts b/server/replays.ts index 8be91e4a6202..510df3ba95e4 100644 --- a/server/replays.ts +++ b/server/replays.ts @@ -111,7 +111,7 @@ export const Replays = new class { const replayData = this.toReplayRow(replay); try { // Retry the insert operation up to 3 times with a 1-second delay between attempts - await retry(() => replays.insert(replayData), 3, 1000); + await this.retry(() => replays.insert(replayData), 3, 1000); for (const playerName of replay.players) { await replayPlayers.insert({ playerid: toID(playerName),