분산 워커 관측 Part C — useNodeStatus 3초 폴링 훅 + statusVisual 색/라벨 매핑 + 2D 워커 카드 그리드 + raw three.js 파이프라인 시각화(정상=시안 파티클 흐름 / busy=가속 / paused=앰버 정지 / degraded=주황 / down=빨강 끊김, Redis 끊김=버스 빨강). GET /api/agent-office/nodes(Part B) 소비. r3f 대신 기설치 three 직접 사용. WebGL 미지원 시 카드 폴백 + 3D/그리드 토글. vitest 10 passed, build OK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019LV86jBozkNhSFXJA412fq
40 lines
1.2 KiB
JavaScript
40 lines
1.2 KiB
JavaScript
// src/pages/infra/useNodeStatus.js
|
|
// /api/agent-office/nodes 를 주기 폴링하는 훅. 3초 권장(Three.js 흐름과 동기).
|
|
import { useEffect, useState, useRef, useCallback } from 'react';
|
|
import { getNodeStatus } from '../../api';
|
|
|
|
export function useNodeStatus(intervalMs = 4000) {
|
|
const [data, setData] = useState(null);
|
|
const [error, setError] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [updatedAt, setUpdatedAt] = useState(null);
|
|
const aliveRef = useRef(true);
|
|
|
|
const tick = useCallback(async () => {
|
|
try {
|
|
const d = await getNodeStatus();
|
|
if (!aliveRef.current) return;
|
|
setData(d);
|
|
setError(null);
|
|
setUpdatedAt(Date.now());
|
|
} catch (e) {
|
|
if (!aliveRef.current) return;
|
|
setError(e);
|
|
} finally {
|
|
if (aliveRef.current) setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
aliveRef.current = true;
|
|
tick();
|
|
const id = setInterval(tick, intervalMs);
|
|
return () => {
|
|
aliveRef.current = false;
|
|
clearInterval(id);
|
|
};
|
|
}, [tick, intervalMs]);
|
|
|
|
return { data, error, loading, updatedAt, refresh: tick };
|
|
}
|