UNPKG

@paroicms/server

Version:
96 lines 3.4 kB
import { ApiError } from "@paroicms/public-server-lib"; import { registeredSites } from "../context.js"; import { isShuttingDown } from "../maintenance/shutdown.js"; import { initializeRequestTracker, setRequestTrackerState, waitForPendingRequests, } from "../request-tracking/request-state.js"; import { loadSiteContext } from "./load-site-context.js"; const MAX_IDLE_TIME = 1000 * 60 * 20; const promises = new Map(); const activeContextAndTimes = new Map(); export function getActiveSiteContexts() { return Array.from(activeContextAndTimes.values()).map((item) => item.siteContext); } export function getActiveSiteContext(fqdn, options = {}) { const item = activeContextAndTimes.get(fqdn); if (item) { updateLastUseTime(fqdn); return item.siteContext; } if (options.returnsUndef) return; throw new Error(`should have the site-context for '${fqdn}'`); } export function getSiteContext(fqdn, options = {}) { if (isShuttingDown()) throw new ApiError("Server shutting down", 503); let promise = promises.get(fqdn); if (promise) { updateLastUseTime(fqdn); } else { const regSite = registeredSites.get(fqdn); if (!regSite) { if (options.returnsUndef) return Promise.resolve(undefined); throw new ApiError(`Site not found: "${fqdn}"`, 404); } promise = wrapCreateSiteContext(regSite); promises.set(fqdn, promise); } return promise; } export async function unloadSiteContext(siteContext) { const { logger } = siteContext; if (siteContext.status === "migration") { await siteContext.cn.destroy(); } else if (siteContext.status === "ready") { setRequestTrackerState(siteContext, "gracefulShutdown"); await waitForPendingRequests(siteContext, 30_000); await siteContext.cn.destroy(); await siteContext.textCache.close(); await siteContext.imageCache.close(); await siteContext.mediaStorage.close(); } else { throw new Error(`Invalid site context status "${siteContext.status}"`); } promises.delete(siteContext.fqdn); activeContextAndTimes.delete(siteContext.fqdn); logger.info("Site unloaded ↘"); } async function wrapCreateSiteContext(regSite) { const siteContext = await loadSiteContext(regSite); if (siteContext.status === "ready") { initializeRequestTracker(siteContext); } activeContextAndTimes.set(regSite.fqdn, { siteContext, lastUseTimeMs: Date.now(), }); siteContext.logger.info("Site loaded ↗"); return siteContext; } function updateLastUseTime(fqdn) { const item = activeContextAndTimes.get(fqdn); if (item) { item.lastUseTimeMs = Date.now(); } } export function watchForIdleSiteContexts() { const intervalId = setInterval(closeIdlingSiteContexts, 1000 * 60 * 5); intervalId.unref(); } async function closeIdlingSiteContexts() { const limit = Date.now() - MAX_IDLE_TIME; for (const { lastUseTimeMs, siteContext } of activeContextAndTimes.values()) { if (lastUseTimeMs >= limit) continue; try { await unloadSiteContext(siteContext); } catch (error) { siteContext.logger.error("Error unloading site", error); } } } //# sourceMappingURL=site-context.js.map