Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions lxl-web/src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import fs from 'fs';
import { type HandleServerError, redirect, type RequestEvent } from '@sveltejs/kit';
import {
type HandleServerError,
redirect,
type RequestEvent,
type ServerInit
} from '@sveltejs/kit';
import { env } from '$env/dynamic/private';
import { defaultLocale, Locales } from '$lib/i18n/locales';
import { DERIVED_LENSES } from '$lib/types/display';
Expand All @@ -20,16 +25,24 @@ import { updateSettings } from '$lib/utils/userSettings.svelte';

type QualifierSuggestionsByLocale = Record<keyof typeof Locales, QualifierSuggestion2[]>;
type Util = [VocabUtil, DisplayUtil, QualifierSuggestionsByLocale];
let utilCache: Util | undefined;
let initLibraries: boolean = false;
let utilCache: Promise<Util> | undefined;

// Warm up caches immediately on startup instead of waiting for a request
export const init: ServerInit = async () => {
try {
const [, displayUtil] = await loadUtilCached();
startRefreshLibraries(displayUtil, defaultLocale);
} catch (err) {
// This is OK, handle() will retry
console.error('Startup initialization failed:', err);
}
};

export const handle = async ({ event, resolve }) => {
const [vocabUtil, displayUtil, qualifierSuggestionsByLocale] = await loadUtilCached();

if (!initLibraries) {
initLibraries = true;
await startRefreshLibraries(displayUtil, defaultLocale);
}
// Fallback in case startup init failed. No-op if refresh already started.
startRefreshLibraries(displayUtil, defaultLocale);

event.locals.vocab = vocabUtil;
event.locals.display = displayUtil;
Expand Down Expand Up @@ -192,9 +205,12 @@ function isValidMyLibraries(value: unknown): value is MyLibrariesType {
return true;
}

async function loadUtilCached() {
function loadUtilCached() {
if (!utilCache) {
utilCache = await loadUtil();
utilCache = loadUtil().catch((err) => {
utilCache = undefined;
throw err;
});
}
return utilCache;
}
Expand Down
39 changes: 34 additions & 5 deletions lxl-web/src/lib/utils/getLibraries.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ let librariesCache: LibrariesCache = new Map();
let orgCache: OrgCache = new Map();

const REFRESH_INTERVAL = 12 * 60 * 60 * 1000; // 12 hrs?
const RETRY_INTERVAL = 30 * 1000; // retry every 30s until the first successful load
let intervalStarted = false;
let firstAttemptStarted = false;
let retryScheduled = false;

async function fetchLibOrgs() {
const orgsArr = (await doFetch('bibdb:Organization')) as LibOrg[];
Expand Down Expand Up @@ -155,17 +158,43 @@ export async function refreshLibraries(displayUtil: DisplayUtil, locale: LocaleC
orgCache = buildOrgIndex(libraries, orgs);
}

export async function startRefreshLibraries(displayUtil: DisplayUtil, locale: LocaleCode) {
export function startRefreshLibraries(displayUtil: DisplayUtil, locale: LocaleCode) {
if (firstAttemptStarted) return;
firstAttemptStarted = true;

// If first refresh on startup fails, keep trying every 30s and don't
// schedule the regular refresh interval until this has succeeded
refreshLibraries(displayUtil, locale)
.then(() => scheduleRefreshInterval(displayUtil, locale))
.catch((err) => {
console.error('Initial library fetch failed:', err);
scheduleRetryUntilInitialized(displayUtil, locale);
});
}

function scheduleRefreshInterval(displayUtil: DisplayUtil, locale: LocaleCode) {
if (intervalStarted) return; // avoid multiple intervals
intervalStarted = true;

refreshLibraries(displayUtil, locale).catch((err) =>
console.error('Initial library fetch failed:', err)
);

setInterval(() => {
refreshLibraries(displayUtil, locale).catch((err) =>
console.error('Scheduled library refresh failed:', err)
);
}, REFRESH_INTERVAL).unref();
}

function scheduleRetryUntilInitialized(displayUtil: DisplayUtil, locale: LocaleCode) {
if (retryScheduled) return;
retryScheduled = true;

const timer: NodeJS.Timeout = setInterval(() => {
refreshLibraries(displayUtil, locale)
.then(() => {
clearInterval(timer);
retryScheduled = false;
scheduleRefreshInterval(displayUtil, locale);
})
.catch((err) => console.error('Library fetch retry failed:', err));
}, RETRY_INTERVAL);
timer.unref();
}
Loading