diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d3b886dbb494f848abd45384fc9193f62c9390..9806e0305c7c931a2ad025a703a852ad6bb183a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - ã‚¨ãƒ©ãƒ¼æ™‚ã‚„é …ç›®ãŒå˜åœ¨ã—ãªã„ã¨ããªã©ã®ã‚¢ã‚¤ã‚³ãƒ³ç”»åƒã‚’サーãƒãƒ¼ç®¡ç†è€…ãŒè¨å®šã§ãるよã†ã«ãªã‚Šã¾ã—㟠### Server +- Fix: ã‚ャッシュãŒæºœã¾ã‚Šç¶šã‘ãªã„よã†ã« - Fix: api/metaã§`TypeError: JSON5.parse is not a function`エラーãŒç™ºç”Ÿã™ã‚‹å•é¡Œã‚’ä¿®æ£ ## 13.13.0 diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index de33e4c243de2357cc239393cc10762cc95390fa..2b7f9a48dabdfc3c5c534fee36454f350419cb73 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -168,6 +168,17 @@ export class CacheService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); + this.userByIdCache.dispose(); + this.localUserByNativeTokenCache.dispose(); + this.localUserByIdCache.dispose(); + this.uriPersonCache.dispose(); + this.userProfileCache.dispose(); + this.userMutingsCache.dispose(); + this.userBlockingCache.dispose(); + this.userBlockedCache.dispose(); + this.renoteMutingsCache.dispose(); + this.userFollowingsCache.dispose(); + this.userFollowingChannelsCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts index 3499df38b763521cce5c7085888ed98d4ea9e7a1..5f2ced77eb61a0c94d9b6b2947a4b5afb8cb7191 100644 --- a/packages/backend/src/core/CustomEmojiService.ts +++ b/packages/backend/src/core/CustomEmojiService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DataSource, In, IsNull } from 'typeorm'; import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; @@ -18,7 +18,7 @@ import type { Serialized } from '@/server/api/stream/types.js'; const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/; @Injectable() -export class CustomEmojiService { +export class CustomEmojiService implements OnApplicationShutdown { private cache: MemoryKVCache<Emoji | null>; public localEmojisCache: RedisSingleCache<Map<string, Emoji>>; @@ -349,4 +349,14 @@ export class CustomEmojiService { this.cache.set(`${emoji.name} ${emoji.host}`, emoji); } } + + @bindThis + public dispose(): void { + this.cache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts index 8b9a87a380ac6a3363e26d256d3386283ea4c12d..3603d59dcc2e263c1eefa6b19249e4af143807d2 100644 --- a/packages/backend/src/core/FederatedInstanceService.ts +++ b/packages/backend/src/core/FederatedInstanceService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; import type { InstancesRepository } from '@/models/index.js'; import type { Instance } from '@/models/entities/Instance.js'; @@ -9,7 +9,7 @@ import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; @Injectable() -export class FederatedInstanceService { +export class FederatedInstanceService implements OnApplicationShutdown { public federatedInstanceCache: RedisKVCache<Instance | null>; constructor( @@ -77,4 +77,14 @@ export class FederatedInstanceService { this.federatedInstanceCache.set(result.host, result); } + + @bindThis + public dispose(): void { + this.federatedInstanceCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index a4c569bdec60d95873c4fcc7de34455f5e3ed5a9..15a1d74878d4686a3644dbcea7de07dbf8abb2c7 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import push from 'web-push'; import * as Redis from 'ioredis'; import { DI } from '@/di-symbols.js'; @@ -42,7 +42,7 @@ function truncateBody<T extends keyof PushNotificationsTypes>(type: T, body: Pus } @Injectable() -export class PushNotificationService { +export class PushNotificationService implements OnApplicationShutdown { private subscriptionsCache: RedisKVCache<SwSubscription[]>; constructor( @@ -115,4 +115,14 @@ export class PushNotificationService { }); } } + + @bindThis + public dispose(): void { + this.subscriptionsCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 40ae106662710270e54dc23ea8360368deac3270..79922d0a87eadded3ec974779f820a359c160eba 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -435,6 +435,7 @@ export class RoleService implements OnApplicationShutdown { @bindThis public dispose(): void { this.redisForSub.off('message', this.onMessage); + this.roleAssignmentByUserIdCache.dispose(); } @bindThis diff --git a/packages/backend/src/core/UserKeypairService.ts b/packages/backend/src/core/UserKeypairService.ts index 72c35c529c2752cff574090eea9ce54ea9972d3a..d768f086503dacf11183a3569f0d8d26ae38d9c2 100644 --- a/packages/backend/src/core/UserKeypairService.ts +++ b/packages/backend/src/core/UserKeypairService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import * as Redis from 'ioredis'; import type { User } from '@/models/entities/User.js'; import type { UserKeypairsRepository } from '@/models/index.js'; @@ -8,7 +8,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; @Injectable() -export class UserKeypairService { +export class UserKeypairService implements OnApplicationShutdown { private cache: RedisKVCache<UserKeypair>; constructor( @@ -31,4 +31,14 @@ export class UserKeypairService { public async getUserKeypair(userId: User['id']): Promise<UserKeypair> { return await this.cache.fetch(userId); } + + @bindThis + public dispose(): void { + this.cache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/core/activitypub/ApDbResolverService.ts b/packages/backend/src/core/activitypub/ApDbResolverService.ts index 2b404ebecaeb64d7ff3a8323a4200436f77b8739..2d9e7a14ee28f751f4231babf3c848edeffd7cd4 100644 --- a/packages/backend/src/core/activitypub/ApDbResolverService.ts +++ b/packages/backend/src/core/activitypub/ApDbResolverService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import escapeRegexp from 'escape-regexp'; import { DI } from '@/di-symbols.js'; import type { NotesRepository, UserPublickeysRepository, UsersRepository } from '@/models/index.js'; @@ -30,7 +30,7 @@ export type UriParseResult = { }; @Injectable() -export class ApDbResolverService { +export class ApDbResolverService implements OnApplicationShutdown { private publicKeyCache: MemoryKVCache<UserPublickey | null>; private publicKeyByUserIdCache: MemoryKVCache<UserPublickey | null>; @@ -162,4 +162,15 @@ export class ApDbResolverService { key, }; } + + @bindThis + public dispose(): void { + this.publicKeyCache.dispose(); + this.publicKeyByUserIdCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } } diff --git a/packages/backend/src/misc/cache.ts b/packages/backend/src/misc/cache.ts index 5610929648b147341cb67d3529abb3c2667e8929..f130a7db8b88f05fa8721b51663a98fdd5cc87c4 100644 --- a/packages/backend/src/misc/cache.ts +++ b/packages/backend/src/misc/cache.ts @@ -83,6 +83,16 @@ export class RedisKVCache<T> { // TODO: イベント発行ã—ã¦ä»–プãƒã‚»ã‚¹ã®ãƒ¡ãƒ¢ãƒªã‚ャッシュも更新ã§ãるよã†ã«ã™ã‚‹ } + + @bindThis + public gc() { + this.memoryCache.gc(); + } + + @bindThis + public dispose() { + this.memoryCache.dispose(); + } } export class RedisSingleCache<T> { @@ -174,10 +184,15 @@ export class RedisSingleCache<T> { export class MemoryKVCache<T> { public cache: Map<string, { date: number; value: T; }>; private lifetime: number; + private gcIntervalHandle: NodeJS.Timer; constructor(lifetime: MemoryKVCache<never>['lifetime']) { this.cache = new Map(); this.lifetime = lifetime; + + this.gcIntervalHandle = setInterval(() => { + this.gc(); + }, 1000 * 60 * 3); } @bindThis @@ -200,7 +215,7 @@ export class MemoryKVCache<T> { } @bindThis - public delete(key: string) { + public delete(key: string): void { this.cache.delete(key); } @@ -255,6 +270,21 @@ export class MemoryKVCache<T> { } return value; } + + @bindThis + public gc(): void { + const now = Date.now(); + for (const [key, { date }] of this.cache.entries()) { + if ((now - date) > this.lifetime) { + this.cache.delete(key); + } + } + } + + @bindThis + public dispose(): void { + clearInterval(this.gcIntervalHandle); + } } export class MemorySingleCache<T> { diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index e23591d8765dfb0e9dd8c3720b5f97a3f2cfd4ec..4ad0197d87d895b72409b3bea4c55fda62e2115c 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import type { AccessTokensRepository, AppsRepository, UsersRepository } from '@/models/index.js'; import type { LocalUser } from '@/models/entities/User.js'; @@ -17,7 +17,7 @@ export class AuthenticationError extends Error { } @Injectable() -export class AuthenticateService { +export class AuthenticateService implements OnApplicationShutdown { private appCache: MemoryKVCache<App>; constructor( @@ -85,4 +85,14 @@ export class AuthenticateService { } } } + + @bindThis + public dispose(): void { + this.appCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } }