perf(renderer): coalesce initial global task refreshes
This commit is contained in:
parent
47cea728b0
commit
174ad83b47
2 changed files with 40 additions and 1 deletions
|
|
@ -247,6 +247,7 @@ const pendingFreshTeamMemberActivityMetaRefreshes = new Set<string>();
|
|||
const pendingTeamPendingReplyRefreshTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
||||
let latestTeamsFetchRequestId = 0;
|
||||
let inFlightGlobalTasksRefresh: Promise<void> | null = null;
|
||||
let inFlightGlobalTasksRefreshScope: ContextRequestScope | null = null;
|
||||
let pendingFreshGlobalTasksRefresh = false;
|
||||
interface RefreshTeamDataOptions {
|
||||
withDedup?: boolean;
|
||||
|
|
@ -1642,7 +1643,13 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
|
||||
fetchAllTasks: async () => {
|
||||
if (inFlightGlobalTasksRefresh) {
|
||||
pendingFreshGlobalTasksRefresh = true;
|
||||
const inFlightScope = inFlightGlobalTasksRefreshScope;
|
||||
if (
|
||||
get().globalTasksInitialized ||
|
||||
(inFlightScope && !isContextRequestScopeCurrent(get, inFlightScope))
|
||||
) {
|
||||
pendingFreshGlobalTasksRefresh = true;
|
||||
}
|
||||
await inFlightGlobalTasksRefresh;
|
||||
return;
|
||||
}
|
||||
|
|
@ -1658,6 +1665,7 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
set({ globalTasksLoading: true, globalTasksError: null });
|
||||
}
|
||||
const requestScope = captureContextRequestScope(get);
|
||||
inFlightGlobalTasksRefreshScope = requestScope;
|
||||
const oldTasks = get().globalTasks;
|
||||
try {
|
||||
const tasks = await withTimeout(
|
||||
|
|
@ -1706,6 +1714,7 @@ export const createTeamSlice: StateCreator<AppState, [], [], TeamSlice> = (set,
|
|||
const request = runRefresh().finally(() => {
|
||||
if (inFlightGlobalTasksRefresh === request) {
|
||||
inFlightGlobalTasksRefresh = null;
|
||||
inFlightGlobalTasksRefreshScope = null;
|
||||
}
|
||||
});
|
||||
inFlightGlobalTasksRefresh = request;
|
||||
|
|
|
|||
|
|
@ -326,6 +326,36 @@ describe('team slice context races', () => {
|
|||
expect(store.getState().globalTasksLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('coalesces concurrent initial global task refreshes for the same context', async () => {
|
||||
const store = createSliceStore();
|
||||
const initialTasks = deferred<GlobalTaskLike[]>();
|
||||
apiMock.teams.getAllTasks.mockReturnValueOnce(initialTasks.promise);
|
||||
|
||||
const firstFetch = store.getState().fetchAllTasks();
|
||||
const secondFetch = store.getState().fetchAllTasks();
|
||||
|
||||
initialTasks.resolve([
|
||||
{
|
||||
id: 'initial-task',
|
||||
subject: 'Initial task',
|
||||
status: 'todo',
|
||||
teamName: 'initial-team',
|
||||
teamDisplayName: 'Initial Team',
|
||||
projectPath: '/initial/project',
|
||||
comments: [],
|
||||
},
|
||||
]);
|
||||
|
||||
await Promise.all([firstFetch, secondFetch]);
|
||||
|
||||
expect(apiMock.teams.getAllTasks).toHaveBeenCalledTimes(1);
|
||||
expect(store.getState().globalTasks).toEqual([
|
||||
expect.objectContaining({ id: 'initial-task', teamName: 'initial-team' }),
|
||||
]);
|
||||
expect(store.getState().globalTasksInitialized).toBe(true);
|
||||
expect(store.getState().globalTasksLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('ignores global tasks loaded before a context epoch reset with the same context id', async () => {
|
||||
const store = createSliceStore();
|
||||
const localTasks = deferred<GlobalTaskLike[]>();
|
||||
|
|
|
|||
Loading…
Reference in a new issue