Merge branch 'cache-metrics' into 'main'

Add cache metrics

See merge request soapbox-pub/ditto!505
This commit is contained in:
Alex Gleason 2024-09-20 17:41:12 +00:00
commit 7c45d13849
6 changed files with 38 additions and 4 deletions

View file

@ -84,3 +84,23 @@ export const dbQueryDurationHistogram = new Histogram({
name: 'ditto_db_query_duration_ms', name: 'ditto_db_query_duration_ms',
help: 'Duration of database queries', help: 'Duration of database queries',
}); });
export const cachedFaviconsSizeGauge = new Gauge({
name: 'ditto_cached_favicons_size',
help: 'Number of domain favicons in cache',
});
export const cachedLnurlsSizeGauge = new Gauge({
name: 'ditto_cached_lnurls_size',
help: 'Number of LNURL details in cache',
});
export const cachedNip05sSizeGauge = new Gauge({
name: 'ditto_cached_nip05s_size',
help: 'Number of NIP-05 results in cache',
});
export const cachedLinkPreviewSizeGauge = new Gauge({
name: 'ditto_cached_link_previews_size',
help: 'Number of link previews in cache',
});

View file

@ -1,6 +1,7 @@
// deno-lint-ignore-file ban-types // deno-lint-ignore-file ban-types
import { LRUCache } from 'lru-cache'; import { LRUCache } from 'lru-cache';
import { type Gauge } from 'prom-client';
type FetchFn<K extends {}, V extends {}, O extends {}> = (key: K, opts: O) => Promise<V>; type FetchFn<K extends {}, V extends {}, O extends {}> = (key: K, opts: O) => Promise<V>;
@ -8,6 +9,10 @@ interface FetchFnOpts {
signal?: AbortSignal | null; signal?: AbortSignal | null;
} }
type SimpleLRUOpts<K extends {}, V extends {}> = LRUCache.Options<K, V, void> & {
gauge?: Gauge;
};
export class SimpleLRU< export class SimpleLRU<
K extends {}, K extends {},
V extends {}, V extends {},
@ -15,7 +20,7 @@ export class SimpleLRU<
> { > {
protected cache: LRUCache<K, V, void>; protected cache: LRUCache<K, V, void>;
constructor(fetchFn: FetchFn<K, V, { signal: AbortSignal }>, opts: LRUCache.Options<K, V, void>) { constructor(fetchFn: FetchFn<K, V, { signal: AbortSignal }>, private opts: SimpleLRUOpts<K, V>) {
this.cache = new LRUCache({ this.cache = new LRUCache({
fetchMethod: (key, _staleValue, { signal }) => fetchFn(key, { signal: signal as unknown as AbortSignal }), fetchMethod: (key, _staleValue, { signal }) => fetchFn(key, { signal: signal as unknown as AbortSignal }),
...opts, ...opts,
@ -24,9 +29,13 @@ export class SimpleLRU<
async fetch(key: K, opts?: O): Promise<V> { async fetch(key: K, opts?: O): Promise<V> {
const result = await this.cache.fetch(key, opts); const result = await this.cache.fetch(key, opts);
this.opts.gauge?.set(this.cache.size);
if (result === undefined) { if (result === undefined) {
throw new Error('SimpleLRU: fetch failed'); throw new Error('SimpleLRU: fetch failed');
} }
return result; return result;
} }

View file

@ -2,6 +2,7 @@ import { DOMParser } from '@b-fuze/deno-dom';
import Debug from '@soapbox/stickynotes/debug'; import Debug from '@soapbox/stickynotes/debug';
import tldts from 'tldts'; import tldts from 'tldts';
import { cachedFaviconsSizeGauge } from '@/metrics.ts';
import { SimpleLRU } from '@/utils/SimpleLRU.ts'; import { SimpleLRU } from '@/utils/SimpleLRU.ts';
import { Time } from '@/utils/time.ts'; import { Time } from '@/utils/time.ts';
import { fetchWorker } from '@/workers/fetch.ts'; import { fetchWorker } from '@/workers/fetch.ts';
@ -37,7 +38,7 @@ const faviconCache = new SimpleLRU<string, URL>(
throw new Error(`Favicon not found: ${key}`); throw new Error(`Favicon not found: ${key}`);
}, },
{ max: 500, ttl: Time.hours(1) }, { max: 500, ttl: Time.hours(1), gauge: cachedFaviconsSizeGauge },
); );
export { faviconCache }; export { faviconCache };

View file

@ -1,6 +1,7 @@
import { LNURL, LNURLDetails } from '@nostrify/nostrify/ln'; import { LNURL, LNURLDetails } from '@nostrify/nostrify/ln';
import Debug from '@soapbox/stickynotes/debug'; import Debug from '@soapbox/stickynotes/debug';
import { cachedLnurlsSizeGauge } from '@/metrics.ts';
import { SimpleLRU } from '@/utils/SimpleLRU.ts'; import { SimpleLRU } from '@/utils/SimpleLRU.ts';
import { Time } from '@/utils/time.ts'; import { Time } from '@/utils/time.ts';
import { fetchWorker } from '@/workers/fetch.ts'; import { fetchWorker } from '@/workers/fetch.ts';
@ -20,7 +21,7 @@ const lnurlCache = new SimpleLRU<string, LNURLDetails>(
throw e; throw e;
} }
}, },
{ max: 1000, ttl: Time.minutes(30) }, { max: 1000, ttl: Time.minutes(30), gauge: cachedLnurlsSizeGauge },
); );
/** Get an LNURL from a lud06 or lud16. */ /** Get an LNURL from a lud06 or lud16. */

View file

@ -4,6 +4,7 @@ import Debug from '@soapbox/stickynotes/debug';
import tldts from 'tldts'; import tldts from 'tldts';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { cachedNip05sSizeGauge } from '@/metrics.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
import { SimpleLRU } from '@/utils/SimpleLRU.ts'; import { SimpleLRU } from '@/utils/SimpleLRU.ts';
import { Time } from '@/utils/time.ts'; import { Time } from '@/utils/time.ts';
@ -43,7 +44,7 @@ const nip05Cache = new SimpleLRU<string, nip19.ProfilePointer>(
throw e; throw e;
} }
}, },
{ max: 500, ttl: Time.hours(1) }, { max: 500, ttl: Time.hours(1), gauge: cachedNip05sSizeGauge },
); );
async function localNip05Lookup(store: NStore, localpart: string): Promise<nip19.ProfilePointer | undefined> { async function localNip05Lookup(store: NStore, localpart: string): Promise<nip19.ProfilePointer | undefined> {

View file

@ -5,6 +5,7 @@ import { unfurl } from 'unfurl.js';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { PreviewCard } from '@/entities/PreviewCard.ts'; import { PreviewCard } from '@/entities/PreviewCard.ts';
import { cachedLinkPreviewSizeGauge } from '@/metrics.ts';
import { Time } from '@/utils/time.ts'; import { Time } from '@/utils/time.ts';
import { fetchWorker } from '@/workers/fetch.ts'; import { fetchWorker } from '@/workers/fetch.ts';
@ -67,6 +68,7 @@ function unfurlCardCached(url: string, signal = AbortSignal.timeout(1000)): Prom
} else { } else {
const card = unfurlCard(url, signal); const card = unfurlCard(url, signal);
previewCardCache.set(url, card); previewCardCache.set(url, card);
cachedLinkPreviewSizeGauge.set(previewCardCache.size);
return card; return card;
} }
} }