Skip to content
Snippets Groups Projects
Commit 73c2b18d authored by richard.petersen's avatar richard.petersen :sailboat: Committed by julian.baeume
Browse files

Create reusable cache.getFile method

parent 4435e282
No related branches found
No related tags found
No related merge requests found
import { createWritable } from './files.js'
import { logger } from './logger.js'
import * as redis from './redis.js'
import { getRedisKey } from './util.js'
import { Gauge } from 'prom-client'
const cache = {}
export const fileCacheSizeGauge = new Gauge({
name: 'file_cache_size',
help: 'Number of entries in file cache'
})
export function set (key, value) {
logger.debug(`[Cache] Set ${key}`)
if (cache[key] === value) return
......@@ -16,6 +24,7 @@ export async function clear () {
for (const prop of Object.getOwnPropertyNames(cache)) {
delete cache[prop]
}
fileCacheSizeGauge.reset()
}
export function get (key, fallback) {
......@@ -51,4 +60,53 @@ export function get (key, fallback) {
return promise
}
export function getCache () { return cache }
export function getFile ({ name, version }, fallback) {
const key = getRedisKey({ version, name })
// try to get the file synchronously.
const data = cache[key]
if (data) {
logger.debug(`[Cache] Resolve file from memory: ${key}`)
return data
}
// if synchronously does not work, store the async promise for further requests
const promise = (async () => {
const bodyKey = getRedisKey({ version, name: `${name}:body` })
const metaKey = getRedisKey({ version, name: `${name}:meta` })
if (redis.isEnabled()) {
const [body, meta = '{}'] = await Promise.all([
redis.client.getBuffer(bodyKey),
redis.client.get(metaKey)
])
if (body) {
logger.debug(`[Cache] Resolve file from redis: ${key}`)
fileCacheSizeGauge.inc()
return (cache[key] = { body, ...JSON.parse(meta) })
}
}
const dataFromServer = await fallback({ version, name }).catch(err => {
if (err.status !== 404) delete cache[key]
throw err
})
if (redis.isEnabled()) {
logger.debug(`[Cache] Store file in redis: ${key}`)
const { body, ...rest } = dataFromServer
redis.client.set(bodyKey, createWritable(body))
redis.client.set(metaKey, JSON.stringify(rest))
}
// overwrite cache with synchronous data
logger.debug(`[Cache] Store file in memory: ${key}`)
fileCacheSizeGauge.inc()
return (cache[key] = dataFromServer)
})()
// temporary set to promise
cache[key] = promise
return promise
}
import { configMap } from './configMap.js'
import { getRedisKey, isJSFile } from './util.js'
import { isJSFile } from './util.js'
import { getCSSDependenciesFor, getViteManifests } from './manifests.js'
import * as cache from './cache.js'
import { logger } from './logger.js'
import { NotFoundError } from './errors.js'
import * as redis from './redis.js'
import zlib from 'node:zlib'
import { promisify } from 'node:util'
import { Gauge } from 'prom-client'
const gzip = promisify(zlib.gzip)
......@@ -15,11 +13,6 @@ const compressFileSize = Number(process.env.COMPRESS_FILE_SIZE)
const compressionMimeTypes = (process.env.COMPRESS_FILE_TYPES || '').replace(/([.+*?^$()[\]{}|])/g, '\\$1').split(' ')
const compressionWhitelistRegex = new RegExp(`^(${compressionMimeTypes.join('|')})($|;)`, 'i')
export const fileCacheSizeGauge = new Gauge({
name: 'file_cache_size',
help: 'Number of entries in file cache'
})
export function createWritable (body) {
if (typeof body !== 'string' && !(body instanceof Buffer)) return JSON.stringify(body)
return body
......@@ -81,51 +74,7 @@ export async function fetchFileWithHeaders ({ path, version }) {
}
export function getFile ({ version, path }) {
const key = getRedisKey({ version, name: `${path}` })
// try to get the file synchronously.
const data = cache.getCache()[key]
if (data) {
logger.debug(`[Files] Resolve from memory: ${key}`)
return data
}
// if synchronously does not work, store the async promise for further requests
const promise = (async () => {
const bodyKey = getRedisKey({ version, name: `${path}:body` })
const metaKey = getRedisKey({ version, name: `${path}:meta` })
if (redis.isEnabled()) {
const [body, meta = '{}'] = await Promise.all([
redis.client.getBuffer(bodyKey),
redis.client.get(metaKey)
])
if (body) {
logger.debug(`[Files] Resolve from redis: ${key}`)
fileCacheSizeGauge.inc()
return (cache.getCache()[key] = { body, ...JSON.parse(meta) })
}
}
const dataFromServer = await fetchFileWithHeaders({ version, path }).catch(err => {
if (err.status !== 404) delete cache.getCache()[key]
throw err
})
if (redis.isEnabled()) {
logger.debug(`[Files] Store in redis: ${key}`)
const { body, ...rest } = dataFromServer
redis.client.set(bodyKey, createWritable(body))
redis.client.set(metaKey, JSON.stringify(rest))
}
// overwrite cache with synchronous data
logger.debug(`[Files] Store in memory: ${key}`)
fileCacheSizeGauge.inc()
return (cache.getCache()[key] = dataFromServer)
})()
// temporary set to promise
cache.getCache()[key] = promise
return promise
return cache.getFile({ name: path, version }, ({ name: path, version }) => {
return fetchFileWithHeaders({ version, path })
})
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment