mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-07 20:44:34 +00:00
add redis cache for note translations
* Partitioned by target language * Invalidated if the note is edited
This commit is contained in:
parent
03b1960e63
commit
7db48ffa8d
1 changed files with 46 additions and 1 deletions
|
@ -6,7 +6,7 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import * as Redis from 'ioredis';
|
import * as Redis from 'ioredis';
|
||||||
import { IsNull } from 'typeorm';
|
import { IsNull } from 'typeorm';
|
||||||
import type { BlockingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, MiUserProfile, UserProfilesRepository, UsersRepository, MiFollowing } from '@/models/_.js';
|
import type { BlockingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, MiUserProfile, UserProfilesRepository, UsersRepository, MiFollowing, MiNote } from '@/models/_.js';
|
||||||
import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js';
|
import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js';
|
||||||
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
@ -22,6 +22,17 @@ export interface FollowStats {
|
||||||
remoteFollowers: number;
|
remoteFollowers: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CachedTranslation {
|
||||||
|
sourceLang: string | undefined;
|
||||||
|
text: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CachedTranslationEntity {
|
||||||
|
l?: string;
|
||||||
|
t?: string;
|
||||||
|
u?: number;
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CacheService implements OnApplicationShutdown {
|
export class CacheService implements OnApplicationShutdown {
|
||||||
public userByIdCache: MemoryKVCache<MiUser>;
|
public userByIdCache: MemoryKVCache<MiUser>;
|
||||||
|
@ -35,6 +46,7 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
public renoteMutingsCache: RedisKVCache<Set<string>>;
|
public renoteMutingsCache: RedisKVCache<Set<string>>;
|
||||||
public userFollowingsCache: RedisKVCache<Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>;
|
public userFollowingsCache: RedisKVCache<Record<string, Pick<MiFollowing, 'withReplies'> | undefined>>;
|
||||||
private readonly userFollowStatsCache = new MemoryKVCache<FollowStats>(1000 * 60 * 10); // 10 minutes
|
private readonly userFollowStatsCache = new MemoryKVCache<FollowStats>(1000 * 60 * 10); // 10 minutes
|
||||||
|
private readonly translationsCache: RedisKVCache<CachedTranslationEntity>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.redis)
|
@Inject(DI.redis)
|
||||||
|
@ -124,6 +136,11 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
fromRedisConverter: (value) => JSON.parse(value),
|
fromRedisConverter: (value) => JSON.parse(value),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.translationsCache = new RedisKVCache<CachedTranslationEntity>(this.redisClient, 'translations', {
|
||||||
|
lifetime: 1000 * 60 * 60 * 24 * 7, // 1 week,
|
||||||
|
memoryCacheLifetime: 1000 * 60, // 1 minute
|
||||||
|
});
|
||||||
|
|
||||||
// NOTE: チャンネルのフォロー状況キャッシュはChannelFollowingServiceで行っている
|
// NOTE: チャンネルのフォロー状況キャッシュはChannelFollowingServiceで行っている
|
||||||
|
|
||||||
this.redisForSub.on('message', this.onMessage);
|
this.redisForSub.on('message', this.onMessage);
|
||||||
|
@ -253,6 +270,34 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async getCachedTranslation(note: MiNote, targetLang: string): Promise<CachedTranslation | null> {
|
||||||
|
const cacheKey = `${note.id}@${targetLang}`;
|
||||||
|
|
||||||
|
// Use cached translation, if present and up-to-date
|
||||||
|
const cached = await this.translationsCache.get(cacheKey);
|
||||||
|
if (cached && cached.u === note.updatedAt?.valueOf()) {
|
||||||
|
return {
|
||||||
|
sourceLang: cached.l,
|
||||||
|
text: cached.t,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// No cache entry :(
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async setCachedTranslation(note: MiNote, targetLang: string, translation: CachedTranslation): Promise<void> {
|
||||||
|
const cacheKey = `${note.id}@${targetLang}`;
|
||||||
|
|
||||||
|
await this.translationsCache.set(cacheKey, {
|
||||||
|
l: translation.sourceLang,
|
||||||
|
t: translation.text,
|
||||||
|
u: note.updatedAt?.valueOf(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this.redisForSub.off('message', this.onMessage);
|
this.redisForSub.off('message', this.onMessage);
|
||||||
|
|
Loading…
Add table
Reference in a new issue