fix: NAS 불가 시 구독자 추천도 클라이언트 Monte Carlo 폴백 처리
- recommend API: fetch 실패/503 시 NAS_UNAVAILABLE 반환 - 추천 페이지: 503 수신 시 클라이언트 Monte Carlo로 폴백 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -76,12 +76,31 @@ export async function GET(req: NextRequest) {
|
|||||||
? '/api/lotto/best'
|
? '/api/lotto/best'
|
||||||
: '/api/lotto/recommend';
|
: '/api/lotto/recommend';
|
||||||
|
|
||||||
const nasRes = await nasGet(nasPath);
|
let nasRes: Response;
|
||||||
|
try {
|
||||||
|
nasRes = await nasGet(nasPath);
|
||||||
|
} catch (fetchErr: unknown) {
|
||||||
|
const e = fetchErr as { name?: string };
|
||||||
|
console.warn('NAS unreachable:', fetchErr);
|
||||||
|
if (e?.name === 'TimeoutError') {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'NAS_UNAVAILABLE', plan: order.product_id, mode },
|
||||||
|
{ status: 503 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'NAS_UNAVAILABLE', plan: order.product_id, mode },
|
||||||
|
{ status: 503 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!nasRes.ok) {
|
if (!nasRes.ok) {
|
||||||
const errText = await nasRes.text();
|
const errText = await nasRes.text();
|
||||||
console.error('NAS API error:', nasRes.status, errText);
|
console.error('NAS API error:', nasRes.status, errText);
|
||||||
return NextResponse.json({ error: 'NAS_API_ERROR' }, { status: 502 });
|
return NextResponse.json(
|
||||||
|
{ error: 'NAS_UNAVAILABLE', plan: order.product_id, mode },
|
||||||
|
{ status: 503 }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nasData = await nasRes.json();
|
const nasData = await nasRes.json();
|
||||||
@@ -94,9 +113,6 @@ export async function GET(req: NextRequest) {
|
|||||||
});
|
});
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
const e = err as { name?: string; message?: string };
|
const e = err as { name?: string; message?: string };
|
||||||
if (e?.name === 'TimeoutError') {
|
|
||||||
return NextResponse.json({ error: 'NAS_TIMEOUT' }, { status: 504 });
|
|
||||||
}
|
|
||||||
if (e?.message === 'NAS_URL_NOT_CONFIGURED') {
|
if (e?.message === 'NAS_URL_NOT_CONFIGURED') {
|
||||||
return NextResponse.json({ error: 'NAS_URL_NOT_CONFIGURED' }, { status: 500 });
|
return NextResponse.json({ error: 'NAS_URL_NOT_CONFIGURED' }, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,6 +285,20 @@ export default function LottoRecommendPage() {
|
|||||||
: '/api/lotto/recommend?mode=single';
|
: '/api/lotto/recommend?mode=single';
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
if (res.status === 403) { setIsSubscribed(false); setProState('idle'); return; }
|
if (res.status === 403) { setIsSubscribed(false); setProState('idle'); return; }
|
||||||
|
|
||||||
|
// NAS 불가 시 클라이언트 Monte Carlo 폴백
|
||||||
|
if (res.status === 503) {
|
||||||
|
const count = genMode === 'batch' ? Math.min(5, MAX_COMBOS - combos.length) : 1;
|
||||||
|
const newCombos: Combo[] = Array.from({ length: count }, () => {
|
||||||
|
idRef.current += 1;
|
||||||
|
const { numbers, metrics } = clientMonteCarlo();
|
||||||
|
return { id: idRef.current, numbers, metrics, createdAt: new Date() };
|
||||||
|
});
|
||||||
|
setCombos((prev) => [...prev, ...newCombos].slice(-MAX_COMBOS));
|
||||||
|
setProState('result');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!res.ok) { const e = await res.json(); throw new Error(e.error ?? 'API_ERROR'); }
|
if (!res.ok) { const e = await res.json(); throw new Error(e.error ?? 'API_ERROR'); }
|
||||||
|
|
||||||
if (genMode === 'batch') {
|
if (genMode === 'batch') {
|
||||||
|
|||||||
Reference in New Issue
Block a user