From 8cdea537e9345475ffe009e7484910440883b5c0 Mon Sep 17 00:00:00 2001 From: dakkar Date: Sun, 30 Jun 2024 10:55:13 +0100 Subject: [PATCH] cache URL previews on the server we already tell browsers to cache the preview for 7 days, but each browser will ask the server, and the server will talk to the network, hammering the poor site that got mentioned on fedi let's instead cache the preview on the server! --- .../src/server/web/UrlPreviewService.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts index 8f8f08a30..23340b293 100644 --- a/packages/backend/src/server/web/UrlPreviewService.ts +++ b/packages/backend/src/server/web/UrlPreviewService.ts @@ -17,20 +17,32 @@ import { bindThis } from '@/decorators.js'; import { ApiError } from '@/server/api/error.js'; import { MiMeta } from '@/models/Meta.js'; import type { FastifyRequest, FastifyReply } from 'fastify'; +import * as Redis from 'ioredis'; +import { RedisKVCache } from '@/misc/cache.js'; @Injectable() export class UrlPreviewService { private logger: Logger; + private previewCache: RedisKVCache; constructor( @Inject(DI.config) private config: Config, + @Inject(DI.redis) + private redisClient: Redis.Redis, + private metaService: MetaService, private httpRequestService: HttpRequestService, private loggerService: LoggerService, ) { this.logger = this.loggerService.getLogger('url-preview'); + this.previewCache = new RedisKVCache(this.redisClient, 'summaly', { + lifetime: 1000 * 86400, + memoryCacheLifetime: 1000 * 10 * 60, + toRedisConverter: (value) => JSON.stringify(value), + fromRedisConverter: (value) => JSON.parse(value), + }); } @bindThis @@ -75,9 +87,19 @@ export class UrlPreviewService { }; } + const key = `${url}@${lang}`; + const cached = await this.previewCache.get(key); + if (cached !== undefined) { + this.logger.info(`Returning cache preview of ${key}`); + // Cache 7days + reply.header('Cache-Control', 'max-age=604800, immutable'); + + return cached; + } + this.logger.info(meta.urlPreviewSummaryProxyUrl - ? `(Proxy) Getting preview of ${url}@${lang} ...` - : `Getting preview of ${url}@${lang} ...`); + ? `(Proxy) Getting preview of ${key} ...` + : `Getting preview of ${key} ...`); try { const summary = meta.urlPreviewSummaryProxyUrl @@ -97,6 +119,8 @@ export class UrlPreviewService { summary.icon = this.wrap(summary.icon); summary.thumbnail = this.wrap(summary.thumbnail); + this.previewCache.set(key, summary); + // Cache 7days reply.header('Cache-Control', 'max-age=604800, immutable');