Skip to content

Commit 471a099

Browse files
committed
Refactor model sync scheduling
1 parent b0b2825 commit 471a099

3 files changed

Lines changed: 43 additions & 39 deletions

File tree

apps/yaak-client/init/sync.ts

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { debounce } from "@yaakapp-internal/lib";
1+
import { debounce, eagerDebounceAsync } from "@yaakapp-internal/lib";
22
import type { AnyModel, ModelPayload } from "@yaakapp-internal/models";
33
import { watchWorkspaceFiles } from "@yaakapp-internal/sync";
44
import { syncWorkspace } from "../commands/commands";
@@ -25,49 +25,16 @@ export async function sync({ force }: { force?: boolean } = {}) {
2525
});
2626
}
2727

28-
const debouncedSync = debounce(async () => {
29-
await sync();
30-
}, 1000);
31-
32-
let modelSyncTimer: ReturnType<typeof setTimeout> | null = null;
33-
let modelSyncInFlight = false;
34-
35-
function scheduleModelSync() {
36-
if (modelSyncTimer == null) {
37-
// No timer means this is the first model change in a burst, so sync immediately.
38-
void syncModelChanges();
39-
} else {
40-
// Keep pushing the trailing sync out until model writes have been quiet for a bit.
41-
clearTimeout(modelSyncTimer);
42-
}
43-
44-
modelSyncTimer = setTimeout(async () => {
45-
modelSyncTimer = null;
46-
// Catch any final state that was written while the immediate sync was running.
47-
await syncModelChanges();
48-
}, 1000);
49-
}
50-
51-
async function syncModelChanges() {
52-
if (modelSyncInFlight) return;
53-
54-
modelSyncInFlight = true;
55-
try {
56-
await sync();
57-
} catch (e) {
58-
console.error(e);
59-
} finally {
60-
modelSyncInFlight = false;
61-
}
62-
}
28+
const syncAfterFileChange = debounce(sync, 1000);
29+
const syncAfterModelWrite = eagerDebounceAsync(sync, 1000);
6330

6431
/**
6532
* Subscribe to model change events. Since we check the workspace ID on sync, we can
6633
* simply add long-lived subscribers for the lifetime of the app.
6734
*/
6835
function initModelListeners() {
6936
listenToTauriEvent<ModelPayload>("model_write", (p) => {
70-
if (isModelRelevant(p.payload.model)) scheduleModelSync();
37+
if (isModelRelevant(p.payload.model)) syncAfterModelWrite();
7138
});
7239
}
7340

@@ -82,11 +49,11 @@ function initFileChangeListeners() {
8249
await unsub?.(); // Unsub to previous
8350
const workspaceMeta = jotaiStore.get(activeWorkspaceMetaAtom);
8451
if (workspaceMeta == null || workspaceMeta.settingSyncDir == null) return;
85-
debouncedSync(); // Perform an initial sync when switching workspace
52+
syncAfterFileChange(); // Perform an initial sync when switching workspace
8653
unsub = watchWorkspaceFiles(
8754
workspaceMeta.workspaceId,
8855
workspaceMeta.settingSyncDir,
89-
debouncedSync,
56+
syncAfterFileChange,
9057
);
9158
});
9259
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
export function eagerDebounceAsync(fn: () => Promise<void>, delay: number) {
2+
let timer: ReturnType<typeof setTimeout> | null = null;
3+
let inFlight: Promise<void> | null = null;
4+
let runAfterInFlight = false;
5+
6+
const run = async () => {
7+
if (inFlight != null) {
8+
runAfterInFlight = true;
9+
return;
10+
}
11+
12+
runAfterInFlight = false;
13+
inFlight = fn()
14+
.catch(console.error)
15+
.finally(() => {
16+
inFlight = null;
17+
if (runAfterInFlight && timer == null) {
18+
void run();
19+
}
20+
});
21+
await inFlight;
22+
};
23+
24+
return () => {
25+
if (timer == null) {
26+
void run();
27+
} else {
28+
clearTimeout(timer);
29+
}
30+
31+
timer = setTimeout(() => {
32+
timer = null;
33+
void run();
34+
}, delay);
35+
};
36+
}

packages/common-lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./debounce";
2+
export * from "./eagerDebounceAsync";
23
export * from "./formatSize";
34
export * from "./templateFunction";

0 commit comments

Comments
 (0)