experiment: SABR 빌드 확대 검증 — 첫 재생은 빠르나 ~55초 뒤 403으로 끊김(적용 불가)

SelfTest 확장: 관찰시간(SELFTEST_WATCH_SEC), 곡전환(SELFTEST_SECOND_QUERY) 지원.
position 샘플링 주기를 Lavalink 보고 주기(5초)에 맞춰 멈춤 오탐 제거.

격리 Lavalink(.9:2334, SABR 빌드) + ytresolver OFF 결과:
  일반곡(K-pop)      성공  첫소리 1455ms  20초 관찰 끊김 0
  해외곡             성공  첫소리 1696ms  20초 관찰 끊김 0
  직접 URL           성공  첫소리  932ms  20초 관찰 끊김 0
  긴 곡(1시간)       성공  첫소리 3865ms  20초 관찰 끊김 0
  플레이리스트(120곡) 성공  첫소리 5656ms  20초 관찰 끊김 0
  곡 전환            성공  (Ditto → HEYA, 6.0s)
  라이브 스트림      실패  ※ 현행 방식(1.18.2+ytresolver)도 동일 실패 → 기존 한계
  장시간 90초        실패  50초 재생 후 정지, 2곡 재현
장시간 실패 원인: 재생 중 googlevideo 403
  (PersistentHttpStream.connect → "Not success status code: 403")
대조군(현행 방식) 동일 90초 테스트: 85초 진행, 끊김 0 → 현행이 안정적.

결론: SABR 빌드는 첫 재생이 약 3초 빠르지만 곡 길이(3~4분)를 못 버티므로 적용 불가.
프로덕션(Lavalink .6, 리졸버, master)은 변경하지 않았다.
This commit is contained in:
2026-09-17 15:08:47 +09:00
parent 4fbf8d9326
commit 7f057d818c
2 changed files with 43 additions and 10 deletions

View File

@@ -45,17 +45,49 @@ export async function runSelfTest() {
Logger.info(`[SelfTest] 재생 요청까지 ${tPlay - t0}ms (검색+해석+리졸브 ${tPlay - tJoin}ms)`);
// 실제 오디오가 흐르는지 확인: position 이 시간에 따라 증가해야 한다.
// SELFTEST_WATCH_SEC 로 관찰 시간을 늘리면 장시간 재생 안정성(중간 끊김)을 검증할 수 있다.
const watchSec = Number(process.env.SELFTEST_WATCH_SEC?.trim() || "9");
// Lavalink 는 position 을 약 5초 주기로 보고하므로 그 주기에 맞춰 샘플링해야 오탐이 없다.
const stepMs = 5000;
const steps = Math.max(3, Math.round((watchSec * 1000) / stepMs));
const samples: number[] = [];
for (let i = 0; i < 6; i++) {
await new Promise((r) => setTimeout(r, 1500));
samples.push(player.position);
Logger.log(`[SelfTest] t+${((i + 1) * 1.5).toFixed(1)}s position=${player.position} isPlaying=${player.isPlaying} track="${player.nowTrack?.info?.title ?? "-"}"`);
let stallCount = 0;
for (let i = 0; i < steps; i++) {
await new Promise((r) => setTimeout(r, stepMs));
const pos = player.position;
if (samples.length > 0 && pos <= samples[samples.length - 1]) stallCount++;
samples.push(pos);
if (i % 3 === 0 || i === steps - 1) {
Logger.log(`[SelfTest] t+${((i + 1) * stepMs / 1000).toFixed(0)}s position=${pos} isPlaying=${player.isPlaying} track="${player.nowTrack?.info?.title ?? "-"}"`);
}
}
const advanced = samples[samples.length - 1] > samples[0] && samples[samples.length - 1] > 0;
if (advanced) {
Logger.ready(`[SelfTest] 결과: 재생 성공 ✅ (position ${samples[0]} → ${samples[samples.length - 1]}, 첫 소리까지 약 ${tPlay - t0}ms)`);
Logger.ready(`[SelfTest] 결과: 재생 성공 ✅ (${(watchSec).toFixed(0)}초 관찰, position ${samples[0]} → ${samples[samples.length - 1]}, 멈춤구간 ${stallCount}/${steps - 1}, 첫 소리까지 약 ${tPlay - t0}ms)`);
} else {
Logger.error(`[SelfTest] 결과: 재생 실패 ❌ (position 이 진행하지 않음: ${samples.join(", ")})`);
Logger.error(`[SelfTest] 결과: 재생 실패 ❌ (position 이 진행하지 않음: ${samples.slice(0, 6).join(", ")})`);
return;
}
// 곡 전환 검증: 두 번째 곡을 큐에 넣고 스킵해서 실제로 다음 곡이 재생되는지 본다.
const secondQuery = process.env.SELFTEST_SECOND_QUERY?.trim();
if (secondQuery) {
const firstTitle = player.nowTrack?.info?.title ?? "";
await lavalinkManager.search(guild.id, secondQuery, client.user?.id ?? "selftest", player);
await new Promise((r) => setTimeout(r, 1500));
const tSkip = Date.now();
player.skip();
let switched = false;
for (let i = 0; i < 10; i++) {
await new Promise((r) => setTimeout(r, 1500));
const cur = player.nowTrack?.info?.title ?? "";
if (cur && cur !== firstTitle && player.position > 0) { switched = true; break; }
}
if (switched) {
Logger.ready(`[SelfTest] 곡전환: 성공 ✅ ("${firstTitle.slice(0, 25)}" → "${(player.nowTrack?.info?.title ?? "").slice(0, 25)}", ${Date.now() - tSkip}ms)`);
} else {
Logger.error(`[SelfTest] 곡전환: 실패 ❌ (다음 곡이 재생되지 않음)`);
}
}
} catch (err) {
Logger.error(`[SelfTest] 예외: ${String(err)}`);

View File

@@ -8,12 +8,13 @@ services:
- ./bot/.env
environment:
- REDIS=false
- LAVALINK_HOST=192.168.10.6
- LAVALINK_PORT=2333
- LAVALINK_HOST=127.0.0.1
- LAVALINK_PORT=2334
- SELFTEST_GUILD_ID=1352269198297923648
- SELFTEST_VOICE_CHANNEL_ID=1352269198914621465
- SELFTEST_TEXT_CHANNEL_ID=1421342055774289980
- SELFTEST_QUERY=LE SSERAFIM CRAZY
- YTRESOLVER_ENABLED=true
- SELFTEST_QUERY=IVE HEYA
- SELFTEST_WATCH_SEC=90
- YTRESOLVER_ENABLED=false
volumes:
- ./testdb:/db