perf: 실시간 접속 확인에서 불필요한 context 조회를 제거

This commit is contained in:
2026-08-16 17:53:25 +00:00
parent dd2ae20167
commit aa51f1b7d9
8 changed files with 148 additions and 78 deletions
+10 -14
View File
@@ -13,7 +13,11 @@ import { useSessionStore } from './session';
import { createLatestRefreshQueue } from '../utils/latestRefreshQueue';
import { createRateLimitedRefreshQueue } from '../utils/rateLimitedRefreshQueue';
import { structurallyShare } from '../utils/structuralShare';
import { createMergedReadModelRefreshQueue } from '../utils/dashboardReadModel';
import {
createMergedReadModelRefreshQueue,
resolveDashboardContextBundleInclude,
type DashboardContextBundleInclude,
} from '../utils/dashboardReadModel';
import { createBroadcastTabCoordinator, type BroadcastTabCoordinator } from '../utils/broadcastTabCoordinator';
import { resolveWithReadModelSnapshotFallback } from '../utils/readModelDeltaRecovery';
@@ -43,11 +47,6 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
type RecentRecord = Awaited<ReturnType<typeof trpc.general.getRecentRecords.query>>['global'][number];
type FrontStatus = Awaited<ReturnType<typeof trpc.general.getFrontStatus.query>>;
type ContextBundleDelta = Awaited<ReturnType<typeof trpc.dashboard.getContextBundleDelta.query>>;
type ContextBundleInclude = {
context: boolean;
commandTable: boolean;
boardAccess: boolean;
};
type DashboardReadModelPatch = {
contextSnapshot?: GeneralContext;
contextRevision?: string | null;
@@ -479,7 +478,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
};
const fetchContextBundlePatch = async (
include: ContextBundleInclude,
include: DashboardContextBundleInclude,
forceSnapshot = false
): Promise<DashboardReadModelPatch> => {
const request = (force: boolean) =>
@@ -637,13 +636,10 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
if (plan.records) recordsError.value = null;
if (plan.frontStatus) frontStatusError.value = null;
try {
const contextPatch = await fetchContextBundlePatch({
// Every automatic refresh crosses this access-limit gate. The
// context delta is usually unchanged and therefore stays small.
context: true,
commandTable: plan.commands,
boardAccess: plan.boardAccess,
});
// Every automatic refresh crosses this access-limit gate before
// any selected follow-up query starts. An all-false bundle is an
// access-only check and does not project general context.
const contextPatch = await fetchContextBundlePatch(resolveDashboardContextBundleInclude(plan));
accessLimited.value = false;
const lobbyPromise = plan.lobby ? trpc.lobby.info.query() : Promise.resolve(undefined);
const mapPromise = plan.map
@@ -9,12 +9,25 @@ import {
export type DashboardReadModelIdentity = RealtimeViewerIdentity;
export type DashboardRefreshPlan = RealtimeReadModelInvalidation;
export type DashboardContextBundleInclude = {
context: boolean;
commandTable: boolean;
boardAccess: boolean;
};
export const resolveDashboardRefreshPlan = (
changes: RealtimeReadModelChanges,
identity: DashboardReadModelIdentity
): DashboardRefreshPlan => resolveRealtimeReadModelInvalidation(changes, identity);
export const resolveDashboardContextBundleInclude = (
plan: DashboardRefreshPlan
): DashboardContextBundleInclude => ({
context: plan.context,
commandTable: plan.commands,
boardAccess: plan.boardAccess,
});
type TimerHandle = ReturnType<typeof setTimeout>;
export interface MergedReadModelRefreshQueue {