fix: Lavalink 노드 미연결 시 unhandledRejection 방지
노드가 CONNECTED 상태가 아닐 때 joinVoiceChannel이 throw 되어 fire-and-forget handleMessage에서 처리되지 않은 Promise 거부로 번지던 문제 수정. - LavalinkManager.hasReadyNode() 추가 - channelJoin에서 노드 미연결 시 안내 임베드 반환 + join try/catch - messageCreate의 handleMessage 호출에 .catch 추가 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,11 @@ export class LavalinkManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 연결 가능한(CONNECTED 상태) Lavalink 노드가 하나라도 있는지 확인 */
|
||||||
|
hasReadyNode(): boolean {
|
||||||
|
return !!this.shoukaku.options.nodeResolver(this.shoukaku.nodes);
|
||||||
|
}
|
||||||
|
|
||||||
getPlayer(guildId: string) {
|
getPlayer(guildId: string) {
|
||||||
return this.players.get(guildId);
|
return this.players.get(guildId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { client, lavalinkManager } from "../index";
|
|||||||
import { Command } from "../types/Command";
|
import { Command } from "../types/Command";
|
||||||
import { GuildPlayer } from "../classes/GuildPlayer";
|
import { GuildPlayer } from "../classes/GuildPlayer";
|
||||||
import { getTextChannelAndMsg } from "../utils/music/Channel";
|
import { getTextChannelAndMsg } from "../utils/music/Channel";
|
||||||
|
import { Logger } from "../utils/Logger";
|
||||||
|
|
||||||
/** join 명령어 */
|
/** join 명령어 */
|
||||||
export default class implements Command {
|
export default class implements Command {
|
||||||
@@ -73,15 +74,38 @@ export async function channelJoin(guild: Guild | null, voiceChannelId: string |
|
|||||||
|
|
||||||
let player = lavalinkManager.getPlayer(guild.id);
|
let player = lavalinkManager.getPlayer(guild.id);
|
||||||
if (player) return { embed: client.mkembed({ title: `이미 <#${player.voiceChannelId}> 참가중입니다.` }), player };
|
if (player) return { embed: client.mkembed({ title: `이미 <#${player.voiceChannelId}> 참가중입니다.` }), player };
|
||||||
player = new GuildPlayer(
|
|
||||||
guild,
|
// 연결 가능한 Lavalink 노드가 없으면 joinVoiceChannel이 throw 되어 unhandledRejection으로 번짐.
|
||||||
await lavalinkManager.shoukaku.joinVoiceChannel({
|
// 노드 미연결 시 사용자에게 안내만 하고 종료.
|
||||||
|
if (!lavalinkManager.hasReadyNode()) {
|
||||||
|
return { embed: client.mkembed({
|
||||||
|
title: "음악 서버에 연결할 수 없습니다.",
|
||||||
|
description: "잠시 후 다시 시도해주세요.",
|
||||||
|
color: "DarkRed",
|
||||||
|
}) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let voicePlayer;
|
||||||
|
try {
|
||||||
|
voicePlayer = await lavalinkManager.shoukaku.joinVoiceChannel({
|
||||||
guildId: guild.id,
|
guildId: guild.id,
|
||||||
channelId: voiceChannel.id,
|
channelId: voiceChannel.id,
|
||||||
shardId: guild.shardId,
|
shardId: guild.shardId,
|
||||||
deaf: true,
|
deaf: true,
|
||||||
mute: false,
|
mute: false,
|
||||||
}),
|
});
|
||||||
|
} catch (err) {
|
||||||
|
Logger.error(`[channelJoin] 음성채널 참가 실패: ${String(err)}`);
|
||||||
|
return { embed: client.mkembed({
|
||||||
|
title: "음성채널 참가에 실패했습니다.",
|
||||||
|
description: "잠시 후 다시 시도해주세요.",
|
||||||
|
color: "DarkRed",
|
||||||
|
}) };
|
||||||
|
}
|
||||||
|
|
||||||
|
player = new GuildPlayer(
|
||||||
|
guild,
|
||||||
|
voicePlayer,
|
||||||
voiceChannel.id,
|
voiceChannel.id,
|
||||||
channel,
|
channel,
|
||||||
msg,
|
msg,
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ const cmdErr = (message: Message, commandName: string | undefined | null): void
|
|||||||
export const messageCreate = async (message: Message): Promise<void> => {
|
export const messageCreate = async (message: Message): Promise<void> => {
|
||||||
if (message.author.bot || message.channel.type === ChannelType.DM) return;
|
if (message.author.bot || message.channel.type === ChannelType.DM) return;
|
||||||
if (!message.content.startsWith(client.prefix)) {
|
if (!message.content.startsWith(client.prefix)) {
|
||||||
handleMessage(message);
|
handleMessage(message).catch((err) => {
|
||||||
|
Logger.error(`[messageCreate] handleMessage 처리 중 에러: ${String(err)}`);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user