perf: dashboard revision-first 조회 계약을 추가
content revision과 별도인 source revision을 선택적으로 교환하고 coverage가 충족될 때만 payload loader를 생략한다. 구형 client와 미완성 producer coverage는 기존 full computation으로 안전하게 복구한다.
This commit is contained in:
@@ -62,6 +62,7 @@ type NavigationFixture = {
|
||||
commandTableKind: string | null;
|
||||
boardAccessKind: string | null;
|
||||
}>;
|
||||
dashboardRequests?: DashboardBundleInput[];
|
||||
};
|
||||
|
||||
type JsonPatchOperation = {
|
||||
@@ -73,6 +74,7 @@ type JsonPatchOperation = {
|
||||
type DashboardBundleInput = {
|
||||
include?: { context?: boolean; commandTable?: boolean; boardAccess?: boolean };
|
||||
known?: { context?: string; commandTable?: string; boardAccess?: string };
|
||||
knownSource?: { context?: string; commandTable?: string; boardAccess?: string };
|
||||
forceSnapshot?: boolean;
|
||||
};
|
||||
|
||||
@@ -389,18 +391,22 @@ const installFixture = async (page: Page, state: NavigationFixture) => {
|
||||
);
|
||||
}
|
||||
const input = operationInput(route, index);
|
||||
(state.dashboardRequests ??= []).push(structuredClone(input));
|
||||
const include = input.include ?? {};
|
||||
const forceSnapshot = input.forceSnapshot === true;
|
||||
if (forceSnapshot) state.forceSnapshotCalls = (state.forceSnapshotCalls ?? 0) + 1;
|
||||
const revision = contextRevision(state);
|
||||
const context = include.context
|
||||
? deltaSlice(
|
||||
generalContext(state),
|
||||
revision,
|
||||
input.known?.context,
|
||||
forceSnapshot,
|
||||
state.contextOperations
|
||||
)
|
||||
? {
|
||||
...deltaSlice(
|
||||
generalContext(state),
|
||||
revision,
|
||||
input.known?.context,
|
||||
forceSnapshot,
|
||||
state.contextOperations
|
||||
),
|
||||
sourceRevision: revision,
|
||||
}
|
||||
: undefined;
|
||||
const currentCommandTableRevision = state.commandTableRevision ?? COMMAND_TABLE_REVISION;
|
||||
const commandTable = include.commandTable
|
||||
@@ -408,6 +414,7 @@ const installFixture = async (page: Page, state: NavigationFixture) => {
|
||||
? {
|
||||
kind: 'snapshot' as const,
|
||||
revision: currentCommandTableRevision,
|
||||
sourceRevision: currentCommandTableRevision,
|
||||
data: commandTableFixture(
|
||||
state.largeCommandTable === true,
|
||||
state.commandBlockedCount,
|
||||
@@ -415,11 +422,16 @@ const installFixture = async (page: Page, state: NavigationFixture) => {
|
||||
),
|
||||
}
|
||||
: input.known.commandTable === currentCommandTableRevision
|
||||
? { kind: 'unchanged' as const, revision: currentCommandTableRevision }
|
||||
? {
|
||||
kind: 'unchanged' as const,
|
||||
revision: currentCommandTableRevision,
|
||||
sourceRevision: currentCommandTableRevision,
|
||||
}
|
||||
: {
|
||||
kind: 'patch' as const,
|
||||
baseRevision: input.known.commandTable,
|
||||
revision: currentCommandTableRevision,
|
||||
sourceRevision: currentCommandTableRevision,
|
||||
operations: state.commandTableOperations ?? [],
|
||||
}
|
||||
: undefined;
|
||||
@@ -428,13 +440,18 @@ const installFixture = async (page: Page, state: NavigationFixture) => {
|
||||
? {
|
||||
kind: 'snapshot' as const,
|
||||
revision: BOARD_ACCESS_REVISION,
|
||||
sourceRevision: BOARD_ACCESS_REVISION,
|
||||
data: {
|
||||
permission: state.permission,
|
||||
canMeeting: state.officerLevel >= 1,
|
||||
canSecret: state.permission >= 2,
|
||||
},
|
||||
}
|
||||
: { kind: 'unchanged' as const, revision: BOARD_ACCESS_REVISION }
|
||||
: {
|
||||
kind: 'unchanged' as const,
|
||||
revision: BOARD_ACCESS_REVISION,
|
||||
sourceRevision: BOARD_ACCESS_REVISION,
|
||||
}
|
||||
: undefined;
|
||||
return response({ context, commandTable, boardAccess });
|
||||
}
|
||||
@@ -2225,6 +2242,18 @@ test('realtime read-model events skip clock-only work, merge bursts, patch in pl
|
||||
boardAccessKind: 'unchanged',
|
||||
});
|
||||
expect(realtimeBundle?.bytes).toBeLessThan(1_000);
|
||||
expect(
|
||||
state.dashboardRequests?.find(
|
||||
(request) =>
|
||||
request.forceSnapshot !== true &&
|
||||
request.include?.context === true &&
|
||||
request.known?.context === CONTEXT_INITIAL_REVISION
|
||||
)?.knownSource
|
||||
).toEqual({
|
||||
context: CONTEXT_INITIAL_REVISION,
|
||||
commandTable: COMMAND_TABLE_REVISION,
|
||||
boardAccess: BOARD_ACCESS_REVISION,
|
||||
});
|
||||
|
||||
const operationsBeforeSurvey = state.operations.length;
|
||||
await page.evaluate(() => {
|
||||
@@ -2248,6 +2277,7 @@ test('realtime read-model events skip clock-only work, merge bursts, patch in pl
|
||||
await expect
|
||||
.poll(() => state.operations.slice(operationsBeforeSurvey), { timeout: 3_000 })
|
||||
.toEqual(['dashboard.getContextBundleDelta', 'general.getFrontStatus']);
|
||||
expect(state.dashboardRequests?.at(-1)?.knownSource?.context).toBe('EEEEEEEEEEEEEEEEEEEEEE');
|
||||
|
||||
const profile = await page.evaluate(() => {
|
||||
const probe = (
|
||||
|
||||
@@ -52,6 +52,9 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
contextRevision?: string | null;
|
||||
commandTableRevision?: string | null;
|
||||
boardAccessRevision?: string | null;
|
||||
contextSourceRevision?: string | null;
|
||||
commandTableSourceRevision?: string | null;
|
||||
boardAccessSourceRevision?: string | null;
|
||||
general?: PresentGeneralContext['general'] | null;
|
||||
city?: PresentGeneralContext['city'] | null;
|
||||
nation?: PresentGeneralContext['nation'] | null;
|
||||
@@ -120,6 +123,9 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
let contextRevision: string | null = null;
|
||||
let commandTableRevision: string | null = null;
|
||||
let boardAccessRevision: string | null = null;
|
||||
let contextSourceRevision: string | null = null;
|
||||
let commandTableSourceRevision: string | null = null;
|
||||
let boardAccessSourceRevision: string | null = null;
|
||||
|
||||
const messageDraftText = ref('');
|
||||
const targetMailbox = ref<number>(MESSAGE_MAILBOX_PUBLIC);
|
||||
@@ -346,6 +352,9 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
resetRecentRecords(null);
|
||||
commandTableRevision = null;
|
||||
boardAccessRevision = null;
|
||||
contextSourceRevision = null;
|
||||
commandTableSourceRevision = null;
|
||||
boardAccessSourceRevision = null;
|
||||
} else if (patch.contextSnapshot !== undefined) {
|
||||
contextSnapshot = patch.contextSnapshot;
|
||||
general.value = structurallyShare(general.value, patch.contextSnapshot.general);
|
||||
@@ -368,6 +377,9 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
contextRevision = null;
|
||||
commandTableRevision = null;
|
||||
boardAccessRevision = null;
|
||||
contextSourceRevision = null;
|
||||
commandTableSourceRevision = null;
|
||||
boardAccessSourceRevision = null;
|
||||
} else if (patch.general !== undefined) {
|
||||
general.value = structurallyShare(general.value, patch.general);
|
||||
}
|
||||
@@ -418,9 +430,24 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
} else if (patch.frontStatus !== undefined) {
|
||||
updateFrontStatus(patch.frontStatus);
|
||||
}
|
||||
if (patch.contextRevision !== undefined) contextRevision = patch.contextRevision;
|
||||
if (patch.commandTableRevision !== undefined) commandTableRevision = patch.commandTableRevision;
|
||||
if (patch.boardAccessRevision !== undefined) boardAccessRevision = patch.boardAccessRevision;
|
||||
if (patch.contextRevision !== undefined) {
|
||||
contextRevision = patch.contextRevision;
|
||||
contextSourceRevision = patch.contextSourceRevision ?? null;
|
||||
} else if (patch.contextSourceRevision !== undefined) {
|
||||
contextSourceRevision = patch.contextSourceRevision;
|
||||
}
|
||||
if (patch.commandTableRevision !== undefined) {
|
||||
commandTableRevision = patch.commandTableRevision;
|
||||
commandTableSourceRevision = patch.commandTableSourceRevision ?? null;
|
||||
} else if (patch.commandTableSourceRevision !== undefined) {
|
||||
commandTableSourceRevision = patch.commandTableSourceRevision;
|
||||
}
|
||||
if (patch.boardAccessRevision !== undefined) {
|
||||
boardAccessRevision = patch.boardAccessRevision;
|
||||
boardAccessSourceRevision = patch.boardAccessSourceRevision ?? null;
|
||||
} else if (patch.boardAccessSourceRevision !== undefined) {
|
||||
boardAccessSourceRevision = patch.boardAccessSourceRevision;
|
||||
}
|
||||
};
|
||||
|
||||
const currentDashboardPatch = (): DashboardReadModelPatch => {
|
||||
@@ -429,6 +456,9 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
patch.contextRevision = contextRevision;
|
||||
patch.commandTableRevision = commandTableRevision;
|
||||
patch.boardAccessRevision = boardAccessRevision;
|
||||
patch.contextSourceRevision = contextSourceRevision;
|
||||
patch.commandTableSourceRevision = commandTableSourceRevision;
|
||||
patch.boardAccessSourceRevision = boardAccessSourceRevision;
|
||||
patch.general = toRaw(general.value);
|
||||
patch.city = toRaw(city.value);
|
||||
patch.nation = toRaw(nation.value);
|
||||
@@ -455,6 +485,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
if (bundle.context) {
|
||||
const applied = applyReadModelDelta(contextSnapshot, contextRevision, bundle.context);
|
||||
patch.contextRevision = applied.revision;
|
||||
patch.contextSourceRevision = applied.sourceRevision ?? null;
|
||||
if (bundle.context.kind !== 'unchanged') {
|
||||
patch.contextSnapshot = applied.data;
|
||||
}
|
||||
@@ -462,6 +493,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
if (bundle.commandTable) {
|
||||
const applied = applyReadModelDelta(commandTableSnapshot, commandTableRevision, bundle.commandTable);
|
||||
patch.commandTableRevision = applied.revision;
|
||||
patch.commandTableSourceRevision = applied.sourceRevision ?? null;
|
||||
if (bundle.commandTable.kind !== 'unchanged') {
|
||||
patch.commandTable = applied.data;
|
||||
}
|
||||
@@ -469,6 +501,7 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
if (bundle.boardAccess) {
|
||||
const applied = applyReadModelDelta(boardAccessSnapshot, boardAccessRevision, bundle.boardAccess);
|
||||
patch.boardAccessRevision = applied.revision;
|
||||
patch.boardAccessSourceRevision = applied.sourceRevision ?? null;
|
||||
if (bundle.boardAccess.kind !== 'unchanged') {
|
||||
patch.boardAccess = applied.data;
|
||||
}
|
||||
@@ -491,6 +524,13 @@ export const useMainDashboardStore = defineStore('mainDashboard', () => {
|
||||
...(commandTableRevision ? { commandTable: commandTableRevision } : {}),
|
||||
...(boardAccessRevision ? { boardAccess: boardAccessRevision } : {}),
|
||||
},
|
||||
knownSource: force
|
||||
? undefined
|
||||
: {
|
||||
...(contextSourceRevision ? { context: contextSourceRevision } : {}),
|
||||
...(commandTableSourceRevision ? { commandTable: commandTableSourceRevision } : {}),
|
||||
...(boardAccessSourceRevision ? { boardAccess: boardAccessSourceRevision } : {}),
|
||||
},
|
||||
forceSnapshot: force || undefined,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user