From 40a6dcb6329512c197dd87fd1543a3dd56156249 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 26 Oct 2023 14:08:19 +0200 Subject: [PATCH] Optimize video views redis calls Try to avoid them if we can --- server/core/lib/redis.ts | 2 +- server/core/lib/views/shared/video-views.ts | 26 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/server/core/lib/redis.ts b/server/core/lib/redis.ts index e986f3141..d06e18fb2 100644 --- a/server/core/lib/redis.ts +++ b/server/core/lib/redis.ts @@ -382,7 +382,7 @@ class Redis { return 'verify-email-registration-' + registrationId } - private generateIPViewKey (ip: string, videoUUID: string) { + generateIPViewKey (ip: string, videoUUID: string) { return `views-${videoUUID}-${ip}` } diff --git a/server/core/lib/views/shared/video-views.ts b/server/core/lib/views/shared/video-views.ts index ee56e30bc..3ce415dbe 100644 --- a/server/core/lib/views/shared/video-views.ts +++ b/server/core/lib/views/shared/video-views.ts @@ -5,11 +5,18 @@ import { getServerActor } from '@server/models/application/application.js' import { MVideo, MVideoImmutable } from '@server/types/models/index.js' import { buildUUID } from '@peertube/peertube-node-utils' import { Redis } from '../../redis.js' +import { LRUCache } from 'lru-cache' +import { VIEW_LIFETIME } from '@server/initializers/constants.js' const lTags = loggerTagsFactory('views') export class VideoViews { + private readonly viewsCache = new LRUCache({ + max: 10_000, + ttl: VIEW_LIFETIME.VIEW + }) + async addLocalView (options: { video: MVideoImmutable ip: string @@ -21,10 +28,10 @@ export class VideoViews { if (!await this.hasEnoughWatchTime(video, watchTime)) return false - const viewExists = await Redis.Instance.doesVideoIPViewExist(ip, video.uuid) + const viewExists = await this.doesVideoIPViewExist(ip, video.uuid) if (viewExists) return false - await Redis.Instance.setIPVideoView(ip, video.uuid) + await this.setIPVideoView(ip, video.uuid) await this.addView(video) @@ -67,4 +74,19 @@ export class VideoViews { // Check more than 50% of the video is watched return duration / watchTime < 2 } + + private doesVideoIPViewExist (ip: string, videoUUID: string) { + const key = Redis.Instance.generateIPViewKey(ip, videoUUID) + const value = this.viewsCache.has(key) + if (value === true) return Promise.resolve(true) + + return Redis.Instance.doesVideoIPViewExist(ip, videoUUID) + } + + private setIPVideoView (ip: string, videoUUID: string) { + const key = Redis.Instance.generateIPViewKey(ip, videoUUID) + this.viewsCache.set(key, true) + + return Redis.Instance.setIPVideoView(ip, videoUUID) + } }