Skip to content

Commit

Permalink
feat: disable cache by default (#1297)
Browse files Browse the repository at this point in the history
  • Loading branch information
haricnugraha authored Jun 21, 2024
1 parent 18ec55c commit 43dfe9b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 38 deletions.
2 changes: 1 addition & 1 deletion dev/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ services:
httpbin:
image: kennethreitz/httpbin
ports:
- 3000:80
- 3002:80
mariadb:
image: mariadb:11
container_name: monika_mariadb
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/guides/cli-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
15 changes: 9 additions & 6 deletions src/components/probe/prober/http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
Expand Down
64 changes: 36 additions & 28 deletions src/components/probe/prober/http/response-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<RequestConfig, string>()

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<ProbeRequestResponse | undefined>(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}`)
}
5 changes: 3 additions & 2 deletions src/flag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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({
Expand Down

0 comments on commit 43dfe9b

Please sign in to comment.