Files
core2026/app/game-frontend/src/composables/useGameServerConnectionRecovery.ts
T
Hide_D c1d5a80f79 fix: 배포 중 화면 유지와 자동 재연결 적용
정상 DEPLOY 중에는 기존 정적 프론트엔드를 유지하고 새 artifact 준비 후 전환합니다. 게임 화면은 일시적인 gateway 오류를 별도 상태로 표시하고 읽기 전용 probe로 제한적으로 복구합니다.
2026-08-27 02:08:44 +00:00

76 lines
2.1 KiB
TypeScript

import { computed, onBeforeUnmount, onMounted, watch } from 'vue';
import { trpc } from '../utils/trpc';
import {
GAME_SERVER_RECONNECTED_EVENT,
gameServerConnection,
retryDelayForFailure,
} from '../utils/gameServerConnection';
export const useGameServerConnectionRecovery = () => {
const reconnecting = computed(() => gameServerConnection.status.value === 'reconnecting');
let retryTimer: ReturnType<typeof setTimeout> | null = null;
let failureCount = 0;
let mounted = false;
let wasReconnecting = false;
const clearRetry = (): void => {
if (retryTimer) clearTimeout(retryTimer);
retryTimer = null;
};
const scheduleRetry = (): void => {
if (!mounted || !reconnecting.value || retryTimer) return;
failureCount += 1;
retryTimer = setTimeout(() => {
retryTimer = null;
void trpc.lobby.info
.query()
.catch(() => undefined)
.finally(() => scheduleRetry());
}, retryDelayForFailure(failureCount));
};
const retryNow = (): void => {
if (!reconnecting.value) return;
clearRetry();
failureCount = 0;
void trpc.lobby.info
.query()
.catch(() => undefined)
.finally(() => scheduleRetry());
};
const stopWatching = watch(
reconnecting,
(current) => {
if (current) {
wasReconnecting = true;
scheduleRetry();
return;
}
clearRetry();
failureCount = 0;
if (wasReconnecting && mounted) {
window.dispatchEvent(new Event(GAME_SERVER_RECONNECTED_EVENT));
}
wasReconnecting = false;
},
{ immediate: true }
);
onMounted(() => {
mounted = true;
window.addEventListener('online', retryNow);
scheduleRetry();
});
onBeforeUnmount(() => {
mounted = false;
clearRetry();
stopWatching();
window.removeEventListener('online', retryNow);
});
return { reconnecting };
};