fix: 재생 exception 시 errMsg 재시도 타이머로 인한 다음 곡 중복 진행 방지

Lavalink는 exception 직후 TrackEndEvent(loadFailed)를 보내 end 핸들러가 다음 곡을
진행시킨다. 기존 exception 핸들러의 errMsg는 5초 뒤 queue[0]을 다시 재생해, 이미
진행된 다음 곡을 재시작시키는 부작용이 있었음.
- errMsg에 retry 파라미터 추가(기본 true). exception 경로는 retry=false로 호출.
- exception이 end를 유발하므로 stopTrack은 부르지 않음(중복 end로 곡 하나 더 스킵 방지).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
tkrmagid
2026-08-17 22:01:53 +09:00
parent 6d79655181
commit 5003c044c5

View File

@@ -103,8 +103,11 @@ export class GuildPlayer {
this.player.on("exception", async (data) => { this.player.on("exception", async (data) => {
try { try {
Logger.error(`[Lavalink] 재생 중 에러 발생: ${data.exception?.message}`); Logger.error(`[Lavalink] 재생 중 에러 발생: ${data.exception?.message}. 다음 곡으로 넘어갑니다.`);
await this.errMsg("유튜브 차단 또는 재생 오류로 인해 이 곡을 건너뜁니다."); // Lavalink는 exception 직후 TrackEndEvent(loadFailed)를 보내므로 end 핸들러가 다음 곡을
// 진행시킨다. 여기서 stopTrack을 부르면 end가 중복 발생해 곡을 하나 더 건너뛰므로,
// 안내만 하고 errMsg의 5초 재시도 타이머는 끈다(retry=false).
await this.errMsg("유튜브 차단 또는 재생 오류로 인해 이 곡을 건너뜁니다.", false);
} catch (err) { } catch (err) {
Logger.error(`[GuildPlayer] exception 이벤트 처리 중 에러: ${String(err)}`); Logger.error(`[GuildPlayer] exception 이벤트 처리 중 에러: ${String(err)}`);
} }
@@ -537,7 +540,7 @@ export class GuildPlayer {
}); });
} }
public async errMsg(reason: string) { public async errMsg(reason: string, retry: boolean = true) {
if (!this.msg) return null; if (!this.msg) return null;
await this.msg.edit({ await this.msg.edit({
content: this.msg.content, content: this.msg.content,
@@ -553,10 +556,14 @@ export class GuildPlayer {
this.queue.length > 1, this.queue.length > 1,
) ] ) ]
}); });
this.errorTimer = setTimeout(() => { // retry=true일 때만 5초 뒤 현재 queue[0]을 재생. 재생 실패(exception)처럼 Lavalink가
this.errorTimer = undefined; // 이미 end 이벤트로 다음 곡을 진행시키는 경우엔 retry=false로 호출해 중복 진행을 막는다.
this.playNext(); if (retry) {
}, DelayAfterErrMs); this.errorTimer = setTimeout(() => {
this.errorTimer = undefined;
this.playNext();
}, DelayAfterErrMs);
}
return null; return null;
} }
} }