diff options
| author | おさむのひと <46447427+samunohito@users.noreply.github.com> | 2023-10-27 18:34:02 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-27 18:34:02 +0900 |
| commit | a8ee67caceb645b83a0857a88009c7b9b1a6e408 (patch) | |
| tree | 2aabd02ea1cbc24cc14a0184327836c2e2a7a49e /packages/backend/src/core/ChannelFollowingService.ts | |
| parent | fix(frontend): ユーザーページの ノート > ファイル付き タブ... (diff) | |
| download | sharkey-a8ee67caceb645b83a0857a88009c7b9b1a6e408.tar.gz sharkey-a8ee67caceb645b83a0857a88009c7b9b1a6e408.tar.bz2 sharkey-a8ee67caceb645b83a0857a88009c7b9b1a6e408.zip | |
Fix: チャンネルのフォロー・アンフォローの反映速度を改善 (#12149)
* チャンネルのフォロー・アンフォローの反映速度を改善
* fix lint
* userFollowingChannelsCacheの場所をCacheServiceからChannelFollowingServiceに移動
---------
Co-authored-by: osamu <46447427+sam-osamu@users.noreply.github.com>
Diffstat (limited to 'packages/backend/src/core/ChannelFollowingService.ts')
| -rw-r--r-- | packages/backend/src/core/ChannelFollowingService.ts | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/packages/backend/src/core/ChannelFollowingService.ts b/packages/backend/src/core/ChannelFollowingService.ts new file mode 100644 index 0000000000..75843b9773 --- /dev/null +++ b/packages/backend/src/core/ChannelFollowingService.ts @@ -0,0 +1,104 @@ +import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; +import Redis from 'ioredis'; +import { DI } from '@/di-symbols.js'; +import type { ChannelFollowingsRepository } from '@/models/_.js'; +import { MiChannel } from '@/models/_.js'; +import { IdService } from '@/core/IdService.js'; +import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js'; +import { bindThis } from '@/decorators.js'; +import type { MiLocalUser } from '@/models/User.js'; +import { RedisKVCache } from '@/misc/cache.js'; + +@Injectable() +export class ChannelFollowingService implements OnModuleInit { + public userFollowingChannelsCache: RedisKVCache<Set<string>>; + + constructor( + @Inject(DI.redis) + private redisClient: Redis.Redis, + @Inject(DI.redisForSub) + private redisForSub: Redis.Redis, + @Inject(DI.channelFollowingsRepository) + private channelFollowingsRepository: ChannelFollowingsRepository, + private idService: IdService, + private globalEventService: GlobalEventService, + ) { + this.userFollowingChannelsCache = new RedisKVCache<Set<string>>(this.redisClient, 'userFollowingChannels', { + lifetime: 1000 * 60 * 30, // 30m + memoryCacheLifetime: 1000 * 60, // 1m + fetcher: (key) => this.channelFollowingsRepository.find({ + where: { followerId: key }, + select: ['followeeId'], + }).then(xs => new Set(xs.map(x => x.followeeId))), + toRedisConverter: (value) => JSON.stringify(Array.from(value)), + fromRedisConverter: (value) => new Set(JSON.parse(value)), + }); + + this.redisForSub.on('message', this.onMessage); + } + + onModuleInit() { + } + + @bindThis + public async follow( + requestUser: MiLocalUser, + targetChannel: MiChannel, + ): Promise<void> { + await this.channelFollowingsRepository.insert({ + id: this.idService.gen(), + followerId: requestUser.id, + followeeId: targetChannel.id, + }); + + this.globalEventService.publishInternalEvent('followChannel', { + userId: requestUser.id, + channelId: targetChannel.id, + }); + } + + @bindThis + public async unfollow( + requestUser: MiLocalUser, + targetChannel: MiChannel, + ): Promise<void> { + await this.channelFollowingsRepository.delete({ + followerId: requestUser.id, + followeeId: targetChannel.id, + }); + + this.globalEventService.publishInternalEvent('unfollowChannel', { + userId: requestUser.id, + channelId: targetChannel.id, + }); + } + + @bindThis + private async onMessage(_: string, data: string): Promise<void> { + const obj = JSON.parse(data); + + if (obj.channel === 'internal') { + const { type, body } = obj.message as GlobalEvents['internal']['payload']; + switch (type) { + case 'followChannel': { + this.userFollowingChannelsCache.refresh(body.userId); + break; + } + case 'unfollowChannel': { + this.userFollowingChannelsCache.delete(body.userId); + break; + } + } + } + } + + @bindThis + public dispose(): void { + this.userFollowingChannelsCache.dispose(); + } + + @bindThis + public onApplicationShutdown(signal?: string | undefined): void { + this.dispose(); + } +} |