Skip to content
Snippets Groups Projects
Commit 4435e282 authored by julian.baeume's avatar julian.baeume :pick:
Browse files

add first dedicated metrics to analyse cache behaviour

this should help to get insights about how the caches are filled locally
parent 20c4e7bb
No related branches found
No related tags found
No related merge requests found
...@@ -7,12 +7,19 @@ import { NotFoundError } from './errors.js' ...@@ -7,12 +7,19 @@ import { NotFoundError } from './errors.js'
import * as redis from './redis.js' import * as redis from './redis.js'
import zlib from 'node:zlib' import zlib from 'node:zlib'
import { promisify } from 'node:util' import { promisify } from 'node:util'
import { Gauge } from 'prom-client'
const gzip = promisify(zlib.gzip) const gzip = promisify(zlib.gzip)
const compressFileSize = Number(process.env.COMPRESS_FILE_SIZE) const compressFileSize = Number(process.env.COMPRESS_FILE_SIZE)
const compressionMimeTypes = (process.env.COMPRESS_FILE_TYPES || '').replace(/([.+*?^$()[\]{}|])/g, '\\$1').split(' ') const compressionMimeTypes = (process.env.COMPRESS_FILE_TYPES || '').replace(/([.+*?^$()[\]{}|])/g, '\\$1').split(' ')
const compressionWhitelistRegex = new RegExp(`^(${compressionMimeTypes.join('|')})($|;)`, 'i') 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) { export function createWritable (body) {
if (typeof body !== 'string' && !(body instanceof Buffer)) return JSON.stringify(body) if (typeof body !== 'string' && !(body instanceof Buffer)) return JSON.stringify(body)
return body return body
...@@ -96,6 +103,7 @@ export function getFile ({ version, path }) { ...@@ -96,6 +103,7 @@ export function getFile ({ version, path }) {
if (body) { if (body) {
logger.debug(`[Files] Resolve from redis: ${key}`) logger.debug(`[Files] Resolve from redis: ${key}`)
fileCacheSizeGauge.inc()
return (cache.getCache()[key] = { body, ...JSON.parse(meta) }) return (cache.getCache()[key] = { body, ...JSON.parse(meta) })
} }
} }
...@@ -113,6 +121,7 @@ export function getFile ({ version, path }) { ...@@ -113,6 +121,7 @@ export function getFile ({ version, path }) {
// overwrite cache with synchronous data // overwrite cache with synchronous data
logger.debug(`[Files] Store in memory: ${key}`) logger.debug(`[Files] Store in memory: ${key}`)
fileCacheSizeGauge.inc()
return (cache.getCache()[key] = dataFromServer) return (cache.getCache()[key] = dataFromServer)
})() })()
......
...@@ -27,7 +27,7 @@ export async function fetchViteManifests () { ...@@ -27,7 +27,7 @@ export async function fetchViteManifests () {
return viteManifests.reduce((memo, manifest) => Object.assign(memo, manifest), {}) return viteManifests.reduce((memo, manifest) => Object.assign(memo, manifest), {})
} }
export function getViteManifests ({ version }) { export async function getViteManifests ({ version }) {
return cache.get(getRedisKey({ version, name: 'viteManifests' }), () => fetchViteManifests()) return cache.get(getRedisKey({ version, name: 'viteManifests' }), () => fetchViteManifests())
} }
......
...@@ -3,9 +3,27 @@ import { getRedisKey, hash } from './util.js' ...@@ -3,9 +3,27 @@ import { getRedisKey, hash } from './util.js'
import { logger } from './logger.js' import { logger } from './logger.js'
import * as cache from './cache.js' import * as cache from './cache.js'
import * as redis from './redis.js' import * as redis from './redis.js'
import { Gauge } from 'prom-client'
import { getViteManifests } from './manifests.js'
let latestVersion let latestVersion
const manifestFileEntriesGauge = new Gauge({
name: 'manifest_file_entries',
help: 'Number of entries in merged vite manifest (number of all known files)',
async collect () {
const version = latestVersion
this.set({ version }, Object.keys(await getViteManifests({ version })).length)
},
labelNames: ['version']
})
const versionUpdateGauge = new Gauge({
name: 'version_update_event',
help: 'Timestamp of a version update event',
labelNames: ['version']
})
export const fetchLatestVersion = async () => { export const fetchLatestVersion = async () => {
const infos = await Promise.all(configMap.urls.map(async baseUrl => { const infos = await Promise.all(configMap.urls.map(async baseUrl => {
try { try {
...@@ -36,6 +54,7 @@ export async function getLatestVersion () { ...@@ -36,6 +54,7 @@ export async function getLatestVersion () {
const version = await redis.client.get(getRedisKey({ name: 'latestVersion' })) const version = await redis.client.get(getRedisKey({ name: 'latestVersion' }))
if (version) { if (version) {
logger.info(`[Version] Got initial version from redis: '${version}'`) logger.info(`[Version] Got initial version from redis: '${version}'`)
versionUpdateGauge.setToCurrentTime({ version })
return (latestVersion = version) return (latestVersion = version)
} }
} }
...@@ -61,6 +80,7 @@ export function registerLatestVersionListener (client) { ...@@ -61,6 +80,7 @@ export function registerLatestVersionListener (client) {
if (channel !== key) return if (channel !== key) return
logger.info(`[Version] Received 'updateLatestVersion' event. Clearing cache. New version: '${version}'`) logger.info(`[Version] Received 'updateLatestVersion' event. Clearing cache. New version: '${version}'`)
await configMap.load() await configMap.load()
versionUpdateGauge.setToCurrentTime({ version })
cache.clear() cache.clear()
latestVersion = version latestVersion = version
}) })
...@@ -73,6 +93,12 @@ export async function updateVersionProcessor () { ...@@ -73,6 +93,12 @@ export async function updateVersionProcessor () {
getLatestVersion(), getLatestVersion(),
fetchLatestVersion() fetchLatestVersion()
]) ])
// don't wait for the data, can be done in background
getViteManifests({ fetchedVersion }).then(manifests => {
manifestFileEntriesGauge.set({ version: fetchedVersion }, Object.keys(manifests).length)
})
if (storedVersion === fetchedVersion) { if (storedVersion === fetchedVersion) {
logger.info(`[Version] No new version has been found. No update needed. Current version: ${storedVersion}`) logger.info(`[Version] No new version has been found. No update needed. Current version: ${storedVersion}`)
return fetchedVersion return fetchedVersion
...@@ -91,6 +117,7 @@ export async function updateVersionProcessor () { ...@@ -91,6 +117,7 @@ export async function updateVersionProcessor () {
await redis.client.set(getRedisKey({ name: 'prevProcessedVersion' }), fetchedVersion) await redis.client.set(getRedisKey({ name: 'prevProcessedVersion' }), fetchedVersion)
} }
} else { } else {
versionUpdateGauge.setToCurrentTime({ version: latestVersion })
// if redis is disabled, this will only be trigger by a setInterval and not from a redis event // if redis is disabled, this will only be trigger by a setInterval and not from a redis event
logger.info('[Version] Clear local cache due to version update.') logger.info('[Version] Clear local cache due to version update.')
cache.clear() cache.clear()
......
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