perf(db): collect planner statistics on connect and after imports

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
jakeandClaude Opus 5.5 committed 2026-10-04 23:18:25 -04:00
1 parent 6620f0b76f
commit 82f0bb11e2
4 files changed
+57

No files matched your search

+7
View File
@@ -13,6 +13,7 @@ import {
getTitleStatusValue,
updateImportJobProgress,
} from "@sofa/db/queries/imports";
import { refreshPlannerStats } from "@sofa/db/queries/maintenance";
import { findEpisodeBySeasonAndNumber, findSeasonByTitleAndNumber } from "@sofa/db/queries/title";
import { createLogger } from "@sofa/logger";
@@ -525,6 +526,12 @@ export async function processImportJob(jobId: string): Promise<void> {
currentMessage: "Import complete",
});
try {
refreshPlannerStats();
} catch (err) {
log.warn("Failed to refresh planner statistics after import:", err);
}
log.info(
`Import job ${jobId} complete: ${result.imported} imported, ${result.skipped} skipped, ${result.failed} failed`,
);
@@ -4,6 +4,7 @@ import { fileURLToPath } from "node:url";
import { beforeEach, describe, expect, test, vi } from "vitest";
import * as maintenance from "@sofa/db/queries/maintenance";
import {
importJobs,
titles,
@@ -162,6 +163,44 @@ describe("processImportJob — movies", () => {
});
});
// ── Planner Statistics ──────────────────────────────────────────────
describe("processImportJob — planner statistics", () => {
function createMovieJob() {
const userId = insertUser();
insertMovieTitle("movie-1", 550, "Fight Club");
const payload: NormalizedImport = {
source: "trakt",
movies: [{ tmdbId: 550, title: "Fight Club", watchedAt: "2024-06-15T20:00:00Z" }],
episodes: [],
watchlist: [],
ratings: [],
};
return createJob(userId, payload);
}
test("refreshes planner statistics once after a successful import", async () => {
const spy = vi.spyOn(maintenance, "refreshPlannerStats");
const jobId = createMovieJob();
await processImportJob(jobId);
expect(spy).toHaveBeenCalledTimes(1);
expect(readImportJob(jobId).status).toBe("success");
});
test("a failing statistics refresh does not fail the import", async () => {
vi.spyOn(maintenance, "refreshPlannerStats").mockImplementation(() => {
throw new Error("boom");
});
const jobId = createMovieJob();
await processImportJob(jobId);
expect(readImportJob(jobId).status).toBe("success");
});
});
// ── Episode Import ──────────────────────────────────────────────────
describe("processImportJob — episodes", () => {