feat: add stats endpoint with cache stats
This commit is contained in:
parent
5ea34f66dd
commit
fd0900e053
7 changed files with 57 additions and 1 deletions
|
|
@ -54,4 +54,11 @@ describe('ExtractorRegistry', () => {
|
|||
const urlResults = await extractorRegistry.handle(ctx, new URL('https://dropload.io/mocked-blocked-2.html'), CountryCode.de, 'a title!');
|
||||
expect(urlResults).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('stats returns something', async () => {
|
||||
const stats = extractorRegistry.stats();
|
||||
|
||||
expect(stats).toHaveProperty('urlResultCache');
|
||||
expect(stats.urlResultCache).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,9 +18,16 @@ export class ExtractorRegistry {
|
|||
this.urlResultCache = new Cacheable({
|
||||
primary: new Keyv({ store: new CacheableMemory({ lruSize: 4096 }) }),
|
||||
secondary: new Keyv(new KeyvSqlite(`sqlite://${getCacheDir()}/webstreamr-extractor-cache.sqlite`)),
|
||||
stats: true,
|
||||
});
|
||||
}
|
||||
|
||||
public stats() {
|
||||
return {
|
||||
urlResultCache: this.urlResultCache.stats,
|
||||
};
|
||||
};
|
||||
|
||||
public async handle(ctx: Context, url: URL, countryCode: CountryCode, title?: string | undefined): Promise<UrlResult[]> {
|
||||
const extractor = this.extractors.find(extractor => !isExtractorDisabled(ctx.config, extractor) && extractor.supports(ctx, url));
|
||||
if (!extractor) {
|
||||
|
|
|
|||
|
|
@ -139,6 +139,14 @@ addon.get('/live', async (req: Request, res: Response) => {
|
|||
}
|
||||
});
|
||||
|
||||
addon.get('/stats', async (_req: Request, res: Response) => {
|
||||
res.json({
|
||||
extractorRegistry: extractorRegistry.stats(),
|
||||
fetcher: fetcher.stats(),
|
||||
sources: Source.stats(),
|
||||
});
|
||||
});
|
||||
|
||||
const port = parseInt(envGet('PORT') || '51546');
|
||||
addon.listen(port, () => {
|
||||
logger.info(`Add-on Repository URL: http://127.0.0.1:${port}/manifest.json`);
|
||||
|
|
|
|||
10
src/source/Source.test.ts
Normal file
10
src/source/Source.test.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { Source } from './Source';
|
||||
|
||||
describe('Source', () => {
|
||||
test('stats returns something', async () => {
|
||||
const stats = Source.stats();
|
||||
|
||||
expect(stats).toHaveProperty('sourceResultCache');
|
||||
expect(stats.sourceResultCache).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -28,10 +28,17 @@ export abstract class Source {
|
|||
private static readonly sourceResultCache = new Cacheable({
|
||||
primary: new Keyv({ store: new CacheableMemory({ lruSize: 1024 }) }),
|
||||
secondary: new Keyv(new KeyvSqlite(`sqlite://${getCacheDir()}/webstreamr-source-cache.sqlite`)),
|
||||
stats: true,
|
||||
});
|
||||
|
||||
protected abstract handleInternal(ctx: Context, type: ContentType, id: Id): Promise<(SourceResult[])>;
|
||||
|
||||
public static stats() {
|
||||
return {
|
||||
sourceResultCache: Source.sourceResultCache.stats,
|
||||
};
|
||||
};
|
||||
|
||||
public async handle(ctx: Context, type: ContentType, id: Id): Promise<(SourceResult[])> {
|
||||
const cacheKey = `${this.id}_${id.toString()}`;
|
||||
|
||||
|
|
|
|||
|
|
@ -258,4 +258,11 @@ describe('fetch', () => {
|
|||
await expect(fetcher.text(ctx, new URL('https://too-many-recent-timeouts-url.test/'), { timeout: 10, timeoutsCountThrow: 2 })).rejects.toBeInstanceOf(TimeoutError);
|
||||
await expect(fetcher.text(ctx, new URL('https://too-many-recent-timeouts-url.test/'), { timeout: 10, timeoutsCountThrow: 2 })).rejects.toBeInstanceOf(TooManyTimeoutsError);
|
||||
});
|
||||
|
||||
test('stats returns something', async () => {
|
||||
const stats = fetcher.stats();
|
||||
|
||||
expect(stats).toHaveProperty('httpCache');
|
||||
expect(stats.httpCache).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -63,7 +63,11 @@ export class Fetcher {
|
|||
|
||||
private readonly logger: winston.Logger;
|
||||
|
||||
private readonly httpCache = new Cacheable({ primary: new Keyv({ store: new CacheableMemory({ lruSize: 2048 }) }) });
|
||||
private readonly httpCache = new Cacheable({
|
||||
primary: new Keyv({ store: new CacheableMemory({ lruSize: 2048 }) }),
|
||||
stats: true,
|
||||
});
|
||||
|
||||
private readonly rateLimitedCache = new Cacheable({ primary: new Keyv({ store: new CacheableMemory({ lruSize: 1024 }) }) });
|
||||
private readonly semaphores = new Map<string, SemaphoreInterface>();
|
||||
private readonly hostUserAgentMap = new Map<string, string>();
|
||||
|
|
@ -76,6 +80,12 @@ export class Fetcher {
|
|||
this.logger = logger;
|
||||
}
|
||||
|
||||
public stats() {
|
||||
return {
|
||||
httpCache: this.httpCache.stats,
|
||||
};
|
||||
};
|
||||
|
||||
public async text(ctx: Context, url: URL, init?: CustomRequestInit): Promise<string> {
|
||||
return (await this.cachedFetch(ctx, url, init)).body;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue