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!
This commit is contained in:
dakkar 2024-06-30 10:55:13 +01:00
parent 84e3eae77f
commit 8cdea537e9
1 changed files with 26 additions and 2 deletions

View File

@ -17,20 +17,32 @@ import { bindThis } from '@/decorators.js';
import { ApiError } from '@/server/api/error.js'; import { ApiError } from '@/server/api/error.js';
import { MiMeta } from '@/models/Meta.js'; import { MiMeta } from '@/models/Meta.js';
import type { FastifyRequest, FastifyReply } from 'fastify'; import type { FastifyRequest, FastifyReply } from 'fastify';
import * as Redis from 'ioredis';
import { RedisKVCache } from '@/misc/cache.js';
@Injectable() @Injectable()
export class UrlPreviewService { export class UrlPreviewService {
private logger: Logger; private logger: Logger;
private previewCache: RedisKVCache<SummalyResult>;
constructor( constructor(
@Inject(DI.config) @Inject(DI.config)
private config: Config, private config: Config,
@Inject(DI.redis)
private redisClient: Redis.Redis,
private metaService: MetaService, private metaService: MetaService,
private httpRequestService: HttpRequestService, private httpRequestService: HttpRequestService,
private loggerService: LoggerService, private loggerService: LoggerService,
) { ) {
this.logger = this.loggerService.getLogger('url-preview'); this.logger = this.loggerService.getLogger('url-preview');
this.previewCache = new RedisKVCache<SummalyResult>(this.redisClient, 'summaly', {
lifetime: 1000 * 86400,
memoryCacheLifetime: 1000 * 10 * 60,
toRedisConverter: (value) => JSON.stringify(value),
fromRedisConverter: (value) => JSON.parse(value),
});
} }
@bindThis @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 this.logger.info(meta.urlPreviewSummaryProxyUrl
? `(Proxy) Getting preview of ${url}@${lang} ...` ? `(Proxy) Getting preview of ${key} ...`
: `Getting preview of ${url}@${lang} ...`); : `Getting preview of ${key} ...`);
try { try {
const summary = meta.urlPreviewSummaryProxyUrl const summary = meta.urlPreviewSummaryProxyUrl
@ -97,6 +119,8 @@ export class UrlPreviewService {
summary.icon = this.wrap(summary.icon); summary.icon = this.wrap(summary.icon);
summary.thumbnail = this.wrap(summary.thumbnail); summary.thumbnail = this.wrap(summary.thumbnail);
this.previewCache.set(key, summary);
// Cache 7days // Cache 7days
reply.header('Cache-Control', 'max-age=604800, immutable'); reply.header('Cache-Control', 'max-age=604800, immutable');