Skip to content

Commit f450e27

Browse files
committed
Better sync status reporting
1 parent eb9d4bf commit f450e27

8 files changed

Lines changed: 1975 additions & 77 deletions

File tree

src/api/routes/admin.ts

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import {
44
runMirrorSync,
55
testUpstreamConnection,
66
getMirrorStatus,
7+
getSyncHistory,
8+
syncEvents,
9+
type SyncProgressEvent,
710
} from "../../lib/mirror-sync.js";
811

912
export async function adminRoutes(app: FastifyInstance) {
@@ -28,9 +31,44 @@ export async function adminRoutes(app: FastifyInstance) {
2831
return result;
2932
});
3033

31-
// Trigger a sync manually
34+
// Trigger a sync manually (fire-and-forget, client uses SSE for progress)
3235
app.post("/admin/mirror/sync", async () => {
33-
const result = await runMirrorSync();
34-
return result;
36+
// Start sync in background — don't await
37+
runMirrorSync("manual").catch((err) => {
38+
console.error("[mirror-sync] Unhandled sync error:", err);
39+
});
40+
return { started: true };
41+
});
42+
43+
// SSE endpoint for live sync progress
44+
app.get("/admin/mirror/sync/progress", async (request, reply) => {
45+
reply.raw.writeHead(200, {
46+
"Content-Type": "text/event-stream",
47+
"Cache-Control": "no-cache",
48+
Connection: "keep-alive",
49+
});
50+
51+
function onProgress(event: SyncProgressEvent) {
52+
reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
53+
if (event.type === "done") {
54+
// Give client a moment to process, then close
55+
setTimeout(() => reply.raw.end(), 100);
56+
}
57+
}
58+
59+
syncEvents.on("progress", onProgress);
60+
61+
request.raw.on("close", () => {
62+
syncEvents.off("progress", onProgress);
63+
});
64+
});
65+
66+
// Sync history
67+
app.get("/admin/mirror/history", async (request) => {
68+
const limit = Math.min(
69+
Number((request.query as any)?.limit) || 20,
70+
100,
71+
);
72+
return getSyncHistory(limit);
3573
});
3674
}

0 commit comments

Comments
 (0)