fix(usage): prioritize filter requests over background refreshes
This commit is contained in:
1 parent
ba247159da
commit
3f8e9a8433
3 files changed
+45
-1
No files matched your search
@@ -404,6 +404,7 @@ export function UsageRecordsPage() {
|
||||
const loadData = useCallback(
|
||||
(quiet = false, immediate = !quiet) => {
|
||||
if (!quiet) setLoading(true);
|
||||
if (!quiet) return schedulerRef.current!.runForeground(() => executeLoadData(false));
|
||||
return schedulerRef.current!.schedule(() => executeLoadData(quiet), immediate);
|
||||
},
|
||||
[executeLoadData],
|
||||
|
||||
@@ -2,6 +2,7 @@ export function createRefreshScheduler(minIntervalMs = 1_000) {
|
||||
type Task = () => Promise<void>;
|
||||
type Completion = { promise: Promise<void>; resolve: () => void; reject: (error: unknown) => void };
|
||||
let running = false;
|
||||
let foregroundTasks = 0;
|
||||
let completedAt = -Infinity;
|
||||
let pending: Task | null = null;
|
||||
let urgent = false;
|
||||
@@ -9,7 +10,7 @@ export function createRefreshScheduler(minIntervalMs = 1_000) {
|
||||
let timer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const pump = () => {
|
||||
if (running || !pending) return;
|
||||
if (running || foregroundTasks > 0 || !pending) return;
|
||||
if (timer !== null) clearTimeout(timer);
|
||||
timer = null;
|
||||
const delay = urgent ? 0 : Math.max(0, minIntervalMs - (performance.now() - completedAt));
|
||||
@@ -38,6 +39,22 @@ export function createRefreshScheduler(minIntervalMs = 1_000) {
|
||||
};
|
||||
|
||||
return {
|
||||
async runForeground(task: Task): Promise<void> {
|
||||
if (timer !== null) clearTimeout(timer);
|
||||
timer = null;
|
||||
pending = null;
|
||||
urgent = false;
|
||||
completion?.resolve();
|
||||
completion = null;
|
||||
foregroundTasks += 1;
|
||||
try {
|
||||
await task();
|
||||
} finally {
|
||||
foregroundTasks -= 1;
|
||||
completedAt = performance.now();
|
||||
pump();
|
||||
}
|
||||
},
|
||||
schedule(task: Task, immediate = false): Promise<void> {
|
||||
pending = task;
|
||||
urgent ||= immediate;
|
||||
|
||||
@@ -42,6 +42,32 @@ describe('refresh scheduler', () => {
|
||||
expect(performance.now() - started).toBeGreaterThanOrEqual(25);
|
||||
});
|
||||
|
||||
it('starts foreground work immediately and holds trailing background refreshes until it finishes', async () => {
|
||||
const scheduler = createRefreshScheduler(0);
|
||||
const backgroundGate = deferred();
|
||||
const foregroundGate = deferred();
|
||||
const calls: string[] = [];
|
||||
const background = scheduler.schedule(async () => {
|
||||
calls.push('background');
|
||||
await backgroundGate.promise;
|
||||
});
|
||||
const obsolete = scheduler.schedule(async () => { calls.push('obsolete'); });
|
||||
const foreground = scheduler.runForeground(async () => {
|
||||
calls.push('foreground');
|
||||
await foregroundGate.promise;
|
||||
});
|
||||
const trailing = scheduler.schedule(async () => { calls.push('trailing'); }, true);
|
||||
|
||||
expect(calls).toEqual(['background', 'foreground']);
|
||||
await obsolete;
|
||||
backgroundGate.resolve();
|
||||
await background;
|
||||
expect(calls).toEqual(['background', 'foreground']);
|
||||
foregroundGate.resolve();
|
||||
await Promise.all([foreground, trailing]);
|
||||
expect(calls).toEqual(['background', 'foreground', 'trailing']);
|
||||
});
|
||||
|
||||
it('cancels queued work during navigation and accepts a fresh request', async () => {
|
||||
const scheduler = createRefreshScheduler(0);
|
||||
const gate = deferred();
|
||||
|
||||
Reference in new issue
Block a user