llm timeout 수정

This commit is contained in:
Macbook
2026-06-17 15:09:29 +09:00
parent f2ca6d0f3b
commit c7f538c36b
3 changed files with 90 additions and 15 deletions
+74 -14
View File
@@ -118,17 +118,69 @@ async function requestOrThrow<T>(path: string, init?: RequestInit): Promise<T> {
const text = await res.text().catch(() => '');
if (!res.ok) {
let msg = `요청 실패 (${res.status})`;
try {
const j = JSON.parse(text) as { message?: string };
if (j.message) msg = j.message;
} catch { /* plain text */ }
if (!text.startsWith('{') && text) msg = text.slice(0, 200);
if (res.status === 504) {
msg = '게이트웨이 시간 초과(504). LLM 분석은 2~3분 걸릴 수 있습니다. 잠시 후 다시 시도해 주세요.';
} else {
try {
const j = JSON.parse(text) as { message?: string };
if (j.message) msg = j.message;
} catch { /* plain text */ }
if (!text.startsWith('{') && text) {
const plain = text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
if (plain) msg = plain.slice(0, 200);
}
}
throw new Error(msg);
}
if (res.status === 204 || !text) return undefined as T;
return JSON.parse(text) as T;
}
/** LLM·AI 검증 등 장시간 API */
async function requestOrThrowWithTimeout<T>(
path: string,
init?: RequestInit,
timeoutMs = 200_000,
): Promise<T> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const res = await fetch(`${API_BASE}${path}`, {
...init,
signal: controller.signal,
headers: { ...authHeaders(), ...(init?.headers ?? {}) },
});
const text = await res.text().catch(() => '');
if (!res.ok) {
let msg = `요청 실패 (${res.status})`;
if (res.status === 504) {
msg = '게이트웨이 시간 초과(504). LLM 분석은 2~3분 걸릴 수 있습니다. 잠시 후 다시 시도해 주세요.';
} else {
try {
const j = JSON.parse(text) as { message?: string };
if (j.message) msg = j.message;
} catch { /* plain text */ }
if (!text.startsWith('{') && text) {
const plain = text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
if (plain) msg = plain.slice(0, 200);
}
}
throw new Error(msg);
}
if (res.status === 204 || !text) return undefined as T;
return JSON.parse(text) as T;
} catch (e) {
if (e instanceof DOMException && e.name === 'AbortError') {
throw new Error(
`요청 시간 초과(${Math.round(timeoutMs / 1000)}초). LLM이 느리면 설정 > LLM에서 타임아웃을 늘리거나 잠시 후 다시 시도하세요.`,
);
}
throw e;
} finally {
clearTimeout(timer);
}
}
async function request<T>(path: string, init?: RequestInit): Promise<T | null> {
try {
const res = await fetch(`${API_BASE}${path}`, {
@@ -1690,11 +1742,15 @@ export interface StrategyEvaluationAiVerifyResponse {
export async function fetchStrategyEvaluationAiVerify(
context: Record<string, unknown>,
): Promise<StrategyEvaluationAiVerifyResponse> {
return requestOrThrow<StrategyEvaluationAiVerifyResponse>('/strategy/evaluation/ai-verify', {
method: 'POST',
cache: 'no-store',
body: JSON.stringify({ context }),
});
return requestOrThrowWithTimeout<StrategyEvaluationAiVerifyResponse>(
'/strategy/evaluation/ai-verify',
{
method: 'POST',
cache: 'no-store',
body: JSON.stringify({ context }),
},
200_000,
);
}
export interface LlmConnectionTestResponse {
@@ -1706,10 +1762,14 @@ export interface LlmConnectionTestResponse {
/** 설정 화면 — LLM 서버 연결 테스트 (저장된 설정 기준) */
export async function fetchLlmConnectionTest(): Promise<LlmConnectionTestResponse> {
return requestOrThrow<LlmConnectionTestResponse>('/strategy/evaluation/llm-test', {
method: 'POST',
cache: 'no-store',
});
return requestOrThrowWithTimeout<LlmConnectionTestResponse>(
'/strategy/evaluation/llm-test',
{
method: 'POST',
cache: 'no-store',
},
130_000,
);
}
/** 전략 DSL에 포함된 평가 시간봉 목록 (실시간 체크·STOMP 구독용) */