From b9d509a9e8e06b314a2679a82fa97686048ac51f Mon Sep 17 00:00:00 2001 From: MyungHyun Date: Thu, 9 Apr 2026 13:48:33 +0900 Subject: [PATCH] fix(fishing): clear stale sessions for deleted threads --- src/services/FishingService.ts | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/services/FishingService.ts b/src/services/FishingService.ts index 19fd9b6..2cca4f8 100644 --- a/src/services/FishingService.ts +++ b/src/services/FishingService.ts @@ -148,7 +148,7 @@ export class FishingService { } const userKey = this.getUserKey(interaction.guildId, interaction.user.id); - const existing = this.sessionsByUser.get(userKey); + const existing = await this.getActiveSession(userKey); if (existing) { return { thread: existing.thread, existed: true }; } @@ -170,7 +170,7 @@ export class FishingService { return false; } - const session = this.sessionsByUser.get(this.getUserKey(interaction.guildId, interaction.user.id)); + const session = await this.getActiveSession(this.getUserKey(interaction.guildId, interaction.user.id)); if (!session) { const thread = await this.findOwnedFishingThread(interaction); if (!thread) { @@ -394,6 +394,39 @@ export class FishingService { } } + private static async getActiveSession(userKey: string) { + const session = this.sessionsByUser.get(userKey); + if (!session) { + return null; + } + + if (await this.isSessionStale(session)) { + this.clearStaleSession(session); + return null; + } + + return session; + } + + private static async isSessionStale(session: FishingSession) { + try { + await session.thread.fetch(); + await session.controlMessage.fetch(); + return false; + } catch (error) { + logger.info( + `[Fishing] Clearing stale session for ${session.userId} in thread ${session.threadId}: ${error instanceof Error ? error.message : String(error)}`, + ); + return true; + } + } + + private static clearStaleSession(session: FishingSession) { + this.clearTick(session); + this.sessionsByUser.delete(this.getUserKey(session.guildId, session.userId)); + this.sessionsByThread.delete(session.threadId); + } + private static async deleteThread(thread: ThreadChannel) { try { await thread.delete();