mirror of
https://codeberg.org/yeentown/barkey.git
synced 2025-07-08 04:54:32 +00:00
clear federatedInstanceCache when meta host lists change
This commit is contained in:
parent
3e7ab07b3c
commit
7385f30903
3 changed files with 56 additions and 26 deletions
|
@ -5,21 +5,24 @@
|
||||||
|
|
||||||
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
|
||||||
import * as Redis from 'ioredis';
|
import * as Redis from 'ioredis';
|
||||||
import type { InstancesRepository } from '@/models/_.js';
|
import type { InstancesRepository, MiMeta } from '@/models/_.js';
|
||||||
import type { MiInstance } from '@/models/Instance.js';
|
import type { MiInstance } from '@/models/Instance.js';
|
||||||
import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js';
|
import { MemoryKVCache } from '@/misc/cache.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import type { GlobalEvents } from '@/core/GlobalEventService.js';
|
||||||
|
import { Serialized } from '@/types.js';
|
||||||
|
import { diffArrays } from '@/misc/diff-arrays.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FederatedInstanceService implements OnApplicationShutdown {
|
export class FederatedInstanceService implements OnApplicationShutdown {
|
||||||
public federatedInstanceCache: RedisKVCache<MiInstance | null>;
|
private readonly federatedInstanceCache: MemoryKVCache<MiInstance | null>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.redis)
|
@Inject(DI.redisForSub)
|
||||||
private redisClient: Redis.Redis,
|
private redisForSub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.instancesRepository)
|
@Inject(DI.instancesRepository)
|
||||||
private instancesRepository: InstancesRepository,
|
private instancesRepository: InstancesRepository,
|
||||||
|
@ -27,30 +30,15 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
) {
|
) {
|
||||||
this.federatedInstanceCache = new RedisKVCache<MiInstance | null>(this.redisClient, 'federatedInstance', {
|
this.federatedInstanceCache = new MemoryKVCache(1000 * 60 * 3); // 3m
|
||||||
lifetime: 1000 * 60 * 30, // 30m
|
this.redisForSub.on('message', this.onMessage);
|
||||||
memoryCacheLifetime: 1000 * 60 * 3, // 3m
|
|
||||||
fetcher: (key) => this.instancesRepository.findOneBy({ host: key }),
|
|
||||||
toRedisConverter: (value) => JSON.stringify(value),
|
|
||||||
fromRedisConverter: (value) => {
|
|
||||||
const parsed = JSON.parse(value);
|
|
||||||
if (parsed == null) return null;
|
|
||||||
return {
|
|
||||||
...parsed,
|
|
||||||
firstRetrievedAt: new Date(parsed.firstRetrievedAt),
|
|
||||||
latestRequestReceivedAt: parsed.latestRequestReceivedAt ? new Date(parsed.latestRequestReceivedAt) : null,
|
|
||||||
infoUpdatedAt: parsed.infoUpdatedAt ? new Date(parsed.infoUpdatedAt) : null,
|
|
||||||
notRespondingSince: parsed.notRespondingSince ? new Date(parsed.notRespondingSince) : null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async fetchOrRegister(host: string): Promise<MiInstance> {
|
public async fetchOrRegister(host: string): Promise<MiInstance> {
|
||||||
host = this.utilityService.toPuny(host);
|
host = this.utilityService.toPuny(host);
|
||||||
|
|
||||||
const cached = await this.federatedInstanceCache.get(host);
|
const cached = this.federatedInstanceCache.get(host);
|
||||||
if (cached) return cached;
|
if (cached) return cached;
|
||||||
|
|
||||||
let index = await this.instancesRepository.findOneBy({ host });
|
let index = await this.instancesRepository.findOneBy({ host });
|
||||||
|
@ -73,7 +61,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
||||||
index = await this.instancesRepository.findOneByOrFail({ host });
|
index = await this.instancesRepository.findOneByOrFail({ host });
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.federatedInstanceCache.set(host, index);
|
this.federatedInstanceCache.set(host, index);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +69,7 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
||||||
public async fetch(host: string): Promise<MiInstance | null> {
|
public async fetch(host: string): Promise<MiInstance | null> {
|
||||||
host = this.utilityService.toPuny(host);
|
host = this.utilityService.toPuny(host);
|
||||||
|
|
||||||
const cached = await this.federatedInstanceCache.get(host);
|
const cached = this.federatedInstanceCache.get(host);
|
||||||
if (cached !== undefined) return cached;
|
if (cached !== undefined) return cached;
|
||||||
|
|
||||||
const index = await this.instancesRepository.findOneBy({ host });
|
const index = await this.instancesRepository.findOneBy({ host });
|
||||||
|
@ -109,8 +97,35 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
||||||
this.federatedInstanceCache.set(result.host, result);
|
this.federatedInstanceCache.set(result.host, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private syncCache(before: Serialized<MiMeta | undefined>, after: Serialized<MiMeta>): void {
|
||||||
|
const changed =
|
||||||
|
hasDiff(before?.blockedHosts, after.blockedHosts) ||
|
||||||
|
hasDiff(before?.silencedHosts, after.silencedHosts) ||
|
||||||
|
hasDiff(before?.mediaSilencedHosts, after.mediaSilencedHosts) ||
|
||||||
|
hasDiff(before?.federationHosts, after.federationHosts) ||
|
||||||
|
hasDiff(before?.bubbleInstances, after.bubbleInstances);
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
// We have to clear the whole thing, otherwise subdomains won't be synced.
|
||||||
|
this.federatedInstanceCache.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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'];
|
||||||
|
if (type === 'metaUpdated') {
|
||||||
|
this.syncCache(body.before, body.after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
this.redisForSub.off('message', this.onMessage);
|
||||||
this.federatedInstanceCache.dispose();
|
this.federatedInstanceCache.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,3 +134,9 @@ export class FederatedInstanceService implements OnApplicationShutdown {
|
||||||
this.dispose();
|
this.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasDiff(before: string[] | null | undefined, after: string[] | null | undefined): boolean {
|
||||||
|
const { added, removed } = diffArrays(before, after);
|
||||||
|
return added.length > 0 || removed.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -609,7 +609,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true,
|
requireSigninToViewContents: user.requireSigninToViewContents === false ? undefined : true,
|
||||||
makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore ?? undefined,
|
makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore ?? undefined,
|
||||||
makeNotesHiddenBefore: user.makeNotesHiddenBefore ?? undefined,
|
makeNotesHiddenBefore: user.makeNotesHiddenBefore ?? undefined,
|
||||||
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
|
instance: user.host ? this.federatedInstanceService.fetch(user.host).then(instance => instance ? {
|
||||||
name: instance.name,
|
name: instance.name,
|
||||||
softwareName: instance.softwareName,
|
softwareName: instance.softwareName,
|
||||||
softwareVersion: instance.softwareVersion,
|
softwareVersion: instance.softwareVersion,
|
||||||
|
|
|
@ -308,8 +308,17 @@ export class MemoryKVCache<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all entries from the cache, but does not dispose it.
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public clear(): void {
|
||||||
|
this.cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
|
this.clear();
|
||||||
clearInterval(this.gcIntervalHandle);
|
clearInterval(this.gcIntervalHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue