mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-16 06:25:42 -04:00
refactor: optimize cron scheduling, DB maintenance, and TMDB reliability
- Skip recommendations refresh for titles fetched within the last 7 days via `getTitlesWithFreshRecommendations`; only stale titles are re-fetched - Replace `Promise.allSettled` in `refreshTvChildren` with a `mapWithConcurrency` helper (concurrency = 5) to stay within TMDB's rate limit - Add 30s request timeout middleware to TMDB client to prevent indefinitely hung fetches - Expand `optimizeDb` weekly job to prune 30-day-old cron runs, integration events, expired sessions, and expired verifications - Add `wal_checkpoint(TRUNCATE)` to `optimizeDatabase` so the WAL is flushed before `PRAGMA optimize` - Add `recoverStaleImportJobs` called on server startup to mark any `pending`/`running` import jobs as errored after a crash/restart - Return `false` from `triggerJob` immediately if the job is already running
This commit is contained in:
17 files changed
+235
-36
No files matched your search
@@ -6,6 +6,7 @@ import {
|
||||
getStaleNonLibraryTitles,
|
||||
getTitleByIdForCron,
|
||||
getTitleIdsWithStaleSeasons,
|
||||
getTitlesWithFreshRecommendations,
|
||||
getTitlesWithStaleOffers,
|
||||
getTitlesWithStaleOffersFetchedBefore,
|
||||
insertCronRunReturning,
|
||||
@@ -53,4 +54,5 @@ export {
|
||||
getReturningTvShows,
|
||||
getTitleByIdForCron,
|
||||
getTitleIdsWithStaleSeasons,
|
||||
getTitlesWithFreshRecommendations,
|
||||
};
|
||||
@@ -63,6 +63,27 @@ import {
|
||||
|
||||
const log = createLogger("metadata");
|
||||
|
||||
async function mapWithConcurrency<T, R>(
|
||||
items: T[],
|
||||
fn: (item: T) => Promise<R>,
|
||||
concurrency: number,
|
||||
): Promise<PromiseSettledResult<R>[]> {
|
||||
const results: PromiseSettledResult<R>[] = Array.from({ length: items.length });
|
||||
let i = 0;
|
||||
async function worker() {
|
||||
while (i < items.length) {
|
||||
const idx = i++;
|
||||
try {
|
||||
results[idx] = { status: "fulfilled", value: await fn(items[idx]) };
|
||||
} catch (reason) {
|
||||
results[idx] = { status: "rejected", reason };
|
||||
}
|
||||
}
|
||||
}
|
||||
await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, worker));
|
||||
return results;
|
||||
}
|
||||
|
||||
export function updateTitleWithArtInvalidation(
|
||||
title: Pick<
|
||||
typeof titles.$inferSelect,
|
||||
@@ -340,10 +361,12 @@ export async function refreshTitle(titleId: string) {
|
||||
}
|
||||
|
||||
export async function refreshTvChildren(titleId: string, tmdbId: number, numberOfSeasons: number) {
|
||||
// Fetch all seasons from TMDB concurrently (~40 req/s rate limit)
|
||||
// Fetch seasons with limited concurrency to stay within TMDB's 40 req/s limit
|
||||
const seasonNumbers = Array.from({ length: numberOfSeasons }, (_, i) => i + 1);
|
||||
const fetched = await Promise.allSettled(
|
||||
seasonNumbers.map((sn) => getTvSeasonDetails(tmdbId, sn)),
|
||||
const fetched = await mapWithConcurrency(
|
||||
seasonNumbers,
|
||||
(sn) => getTvSeasonDetails(tmdbId, sn),
|
||||
5,
|
||||
);
|
||||
|
||||
const now = new Date();
|
||||
|
||||
Reference in new issue
Block a user