diff --git a/dev/docker-compose.yaml b/dev/docker-compose.yaml index a7c678281..a6b23781d 100644 --- a/dev/docker-compose.yaml +++ b/dev/docker-compose.yaml @@ -2,7 +2,7 @@ services: httpbin: image: kennethreitz/httpbin ports: - - 3000:80 + - 3002:80 mariadb: image: mariadb:11 container_name: monika_mariadb diff --git a/docs/src/pages/guides/cli-options.md b/docs/src/pages/guides/cli-options.md index 8268919e0..55967d13c 100644 --- a/docs/src/pages/guides/cli-options.md +++ b/docs/src/pages/guides/cli-options.md @@ -338,7 +338,7 @@ monika --ignoreInvalidTLS ## TTL Cache -Time-to-live for in-memory (HTTP) cache entries in minutes. Defaults to 5 minutes. Setting to 0 means disabling this cache. This cache is used for requests with identical HTTP request config, e.g. headers, method, url. +Enable time-to-live for in-memory (HTTP) cache entries in minutes. This cache is used for requests with identical HTTP request config, e.g. headers, method, url. Only usable for probes which does not have [chaining requests.](https://hyperjumptech.github.io/monika/guides/examples#requests-chaining) diff --git a/src/components/probe/prober/http/index.ts b/src/components/probe/prober/http/index.ts index 9d8b4a544..219fd722b 100644 --- a/src/components/probe/prober/http/index.ts +++ b/src/components/probe/prober/http/index.ts @@ -40,7 +40,7 @@ import { addIncident } from '../../../incident' import { saveProbeRequestLog } from '../../../logger/history' import { logResponseTime } from '../../../logger/response-time-log' import { httpRequest } from './request' -import { getCache, putCache } from './response-cache' +import { get as getCache, put as putCache } from './response-cache' type ProbeResultMessageParams = { request: RequestConfig @@ -57,17 +57,20 @@ export class HTTPProber extends BaseProber { // force fresh request if : // - probe has chaining requests, OR // - this is a retrying attempt - if (requests.length > 1 || incidentRetryAttempt > 0) { + if ( + requests.length > 1 || + incidentRetryAttempt > 0 || + !getContext().flags['ttl-cache'] + ) { for (const requestConfig of requests) { responses.push( // eslint-disable-next-line no-await-in-loop await this.doRequest(requestConfig, signal, responses) ) } - } - // use cached response when possible - // or fallback to fresh request if cache expired - else { + } else { + // use cached response when possible + // or fallback to fresh request if cache expired const responseCache = getCache(requests[0]) const response = responseCache || (await this.doRequest(requests[0], signal, responses)) diff --git a/src/components/probe/prober/http/response-cache.ts b/src/components/probe/prober/http/response-cache.ts index 32abacd7d..f9033d969 100644 --- a/src/components/probe/prober/http/response-cache.ts +++ b/src/components/probe/prober/http/response-cache.ts @@ -22,48 +22,56 @@ * SOFTWARE. * **********************************************************************************/ -import { getContext } from '../../../../context' -import { ProbeRequestResponse, RequestConfig } from 'src/interfaces/request' -import { log } from '../../../../utils/pino' import TTLCache from '@isaacs/ttlcache' import { createHash } from 'crypto' +import { getContext } from '../../../../context' +import type { + ProbeRequestResponse, + RequestConfig, +} from '../../../../interfaces/request' +import { log } from '../../../../utils/pino' const ttlCache = new TTLCache() const cacheHash = new Map() -function getOrCreateHash(config: RequestConfig) { - let hash = cacheHash.get(config) - if (!hash) { - hash = createHash('SHA1').update(JSON.stringify(config)).digest('hex') - } - - return hash -} - -function put(config: RequestConfig, value: ProbeRequestResponse) { - if (!getContext().flags['ttl-cache'] || getContext().isTest) return +export function put(config: RequestConfig, value: ProbeRequestResponse) { const hash = getOrCreateHash(config) // manually set time-to-live for each cache entry // moved from "new TTLCache()" initialization above because corresponding flag is not yet parsed - const ttl = getContext().flags['ttl-cache'] * 60_000 + const minutes = 60_000 + const ttl = getContext().flags['ttl-cache'] * minutes ttlCache.set(hash, value, { ttl }) } -function get(config: RequestConfig): ProbeRequestResponse | undefined { - if (!getContext().flags['ttl-cache'] || getContext().isTest) return undefined +export function get(config: RequestConfig) { const key = getOrCreateHash(config) - const response = ttlCache.get(key) - const isVerbose = getContext().flags['verbose-cache'] - const shortHash = key.slice(Math.max(0, key.length - 7)) - if (isVerbose && response) { - const time = new Date().toISOString() - log.info(`${time} - [${shortHash}] Cache HIT`) - } else if (isVerbose) { - const time = new Date().toISOString() - log.info(`${time} - [${shortHash}] Cache MISS`) + const response = ttlCache.get(key) + + if (getContext().flags['verbose-cache']) { + logVerbose({ response, key }) } - return response as ProbeRequestResponse | undefined + return response } -export { put as putCache, get as getCache } +function getOrCreateHash(config: RequestConfig) { + const hash = cacheHash.get(config) + if (hash) { + return hash + } + + return createHash('SHA1').update(JSON.stringify(config)).digest('hex') +} + +type LogVerbose = { + response: unknown + key: string +} + +function logVerbose({ response, key }: LogVerbose) { + const time = new Date().toISOString() + const shortHash = key.slice(Math.max(0, key.length - 7)) + const message = response ? 'Cache HIT' : 'Cache MISS' + + log.info(`${time} - [${shortHash}] ${message}`) +} diff --git a/src/flag.ts b/src/flag.ts index 847f7a5b2..0d9288e07 100644 --- a/src/flag.ts +++ b/src/flag.ts @@ -100,7 +100,7 @@ export const monikaFlagsDefaultValue: MonikaFlags = { symonGetProbesIntervalMs: 60_000, symonReportInterval: DEFAULT_SYMON_REPORT_INTERVAL_MS, symonReportLimit: 100, - 'ttl-cache': 5, + 'ttl-cache': 0, verbose: false, 'verbose-cache': false, } @@ -281,7 +281,8 @@ export const flags = { exclusive: ['postman', 'insomnia', 'sitemap', 'har'], }), 'ttl-cache': Flags.integer({ - description: `Time-to-live for in-memory (HTTP) cache entries in minutes. Defaults to ${monikaFlagsDefaultValue['ttl-cache']} minutes`, + description: + 'Enables time-to-live for in-memory (HTTP) cache entries in minutes', default: monikaFlagsDefaultValue['ttl-cache'], }), verbose: Flags.boolean({