UNPKG

@cocalc/database

Version:

CoCalc: code for working with our PostgreSQL database

79 lines (78 loc) 2.96 kB
"use strict"; /* * This file is part of CoCalc: Copyright © 2021 Sagemath, Inc. * License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* Caches queries for a certain amount of time. Also, if there are multiple queries coming in at the same time for the same thing, only one actually goes to the database. IMPORTANT: This *only* caches a query if the query actually returns at least one row. If the query returns nothing, that fact is not cached. This is usually what we want, e.g., if somebody access https://cocalc.com/wstein/myproject, and notices that myproject isn't the set name, then they may set it and immediately try https://cocalc.com/wstein/myproject again. In that case, we don't want to the cache to mean that they don't see the page for a while. On the other hand, if querying for the project that myproject resolves to is cached for a minute that is fine, since this would only be a problem when they change the name of multiple projects. */ const lru_cache_1 = __importDefault(require("lru-cache")); const hof_1 = require("async-await-utils/hof"); const pool_1 = __importDefault(require("./pool")); const logger_1 = __importDefault(require("@cocalc/backend/logger")); const L = (0, logger_1.default)("db:pool:cached"); const MAX_AGE_S = { short: 5, medium: 15, long: 30, minutes: 10 * 60, infinite: 60 * 60 * 24 * 365, // effectively forever; e.g., getting path from share id is really just a reversed sha1 hash, so can't change. }; const caches = new Map(); for (const length in MAX_AGE_S) { caches[length] = new lru_cache_1.default({ max: 1000, maxAge: 1000 * MAX_AGE_S[length], }); } const cachedQuery = (0, hof_1.reuseInFlight)(async (length, ...args) => { const cache = caches[length]; if (cache == null) { throw Error(`invalid cache "${length}"`); } const key = JSON.stringify(args); if (cache.has(key)) { // console.log(`YES - using cache for ${key}`); return cache.get(key); } // console.log(`NOT using cache for ${key}`); const pool = (0, pool_1.default)(); try { // @ts-ignore - no clue how to typescript this. const result = await pool.query(...args); if (result.rows.length > 0) { // We only cache query if it returned something. cache.set(key, result); } return result; } catch (err) { L.error(`cachedQuery error: ${err}`); throw err; } }); function getCachedPool(length) { return { query: async (...args) => await cachedQuery(length, ...args), }; // obviously not really a Pool, but is enough for what we're doing. } exports.default = getCachedPool; //# sourceMappingURL=cached.js.map