feat(backend): イベント用Redisを別サーバーに分離できるように
This commit is contained in:
parent
f4588f3907
commit
ff6d9d2860
|
@ -62,6 +62,14 @@ redis:
|
||||||
#prefix: example-prefix
|
#prefix: example-prefix
|
||||||
#db: 1
|
#db: 1
|
||||||
|
|
||||||
|
#redisForPubsub:
|
||||||
|
# host: redis
|
||||||
|
# port: 6379
|
||||||
|
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||||
|
# #pass: example-pass
|
||||||
|
# #prefix: example-prefix
|
||||||
|
# #db: 1
|
||||||
|
|
||||||
# ┌─────────────────────────────┐
|
# ┌─────────────────────────────┐
|
||||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,14 @@ redis:
|
||||||
#prefix: example-prefix
|
#prefix: example-prefix
|
||||||
#db: 1
|
#db: 1
|
||||||
|
|
||||||
|
#redisForPubsub:
|
||||||
|
# host: localhost
|
||||||
|
# port: 6379
|
||||||
|
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||||
|
# #pass: example-pass
|
||||||
|
# #prefix: example-prefix
|
||||||
|
# #db: 1
|
||||||
|
|
||||||
# ┌─────────────────────────────┐
|
# ┌─────────────────────────────┐
|
||||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,14 @@ redis:
|
||||||
#prefix: example-prefix
|
#prefix: example-prefix
|
||||||
#db: 1
|
#db: 1
|
||||||
|
|
||||||
|
#redisForPubsub:
|
||||||
|
# host: redis
|
||||||
|
# port: 6379
|
||||||
|
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||||
|
# #pass: example-pass
|
||||||
|
# #prefix: example-prefix
|
||||||
|
# #db: 1
|
||||||
|
|
||||||
# ┌─────────────────────────────┐
|
# ┌─────────────────────────────┐
|
||||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
- 「UIのアニメーションを減らす」 (`reduceAnimation`) で猫耳を撫でられなくなります
|
- 「UIのアニメーションを減らす」 (`reduceAnimation`) で猫耳を撫でられなくなります
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
- イベント用Redisを別サーバーに分離できるように
|
||||||
- サーバーの全体的なパフォーマンスを向上
|
- サーバーの全体的なパフォーマンスを向上
|
||||||
- ノート作成時のパフォーマンスを向上
|
- ノート作成時のパフォーマンスを向上
|
||||||
- アンテナのタイムライン取得時のパフォーマンスを向上
|
- アンテナのタイムライン取得時のパフォーマンスを向上
|
||||||
|
|
|
@ -78,10 +78,19 @@ db:
|
||||||
redis:
|
redis:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 6379
|
port: 6379
|
||||||
|
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||||
#pass: example-pass
|
#pass: example-pass
|
||||||
#prefix: example-prefix
|
#prefix: example-prefix
|
||||||
#db: 1
|
#db: 1
|
||||||
|
|
||||||
|
#redisForPubsub:
|
||||||
|
# host: localhost
|
||||||
|
# port: 6379
|
||||||
|
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||||
|
# #pass: example-pass
|
||||||
|
# #prefix: example-prefix
|
||||||
|
# #db: 1
|
||||||
|
|
||||||
# ┌─────────────────────────────┐
|
# ┌─────────────────────────────┐
|
||||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
|
import Redis from 'ioredis';
|
||||||
import { loadConfig } from './built/config.js';
|
import { loadConfig } from './built/config.js';
|
||||||
import { createRedisConnection } from './built/redis.js';
|
|
||||||
|
|
||||||
const config = loadConfig();
|
const config = loadConfig();
|
||||||
const redis = createRedisConnection(config);
|
const redis = new Redis({
|
||||||
|
port: config.redis.port,
|
||||||
|
host: config.redis.host,
|
||||||
|
family: config.redis.family == null ? 0 : config.redis.family,
|
||||||
|
password: config.redis.pass,
|
||||||
|
keyPrefix: `${config.redis.prefix}:`,
|
||||||
|
db: config.redis.db ?? 0,
|
||||||
|
});
|
||||||
|
|
||||||
redis.on('connect', () => redis.disconnect());
|
redis.on('connect', () => redis.disconnect());
|
||||||
redis.on('error', (e) => {
|
redis.on('error', (e) => {
|
||||||
|
|
|
@ -2,18 +2,15 @@ import { setTimeout } from 'node:timers/promises';
|
||||||
import { Global, Inject, Module } from '@nestjs/common';
|
import { Global, Inject, Module } from '@nestjs/common';
|
||||||
import Redis from 'ioredis';
|
import Redis from 'ioredis';
|
||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { createRedisConnection } from '@/redis.js';
|
|
||||||
import { DI } from './di-symbols.js';
|
import { DI } from './di-symbols.js';
|
||||||
import { loadConfig } from './config.js';
|
import { loadConfig } from './config.js';
|
||||||
import { createPostgresDataSource } from './postgres.js';
|
import { createPostgresDataSource } from './postgres.js';
|
||||||
import { RepositoryModule } from './models/RepositoryModule.js';
|
import { RepositoryModule } from './models/RepositoryModule.js';
|
||||||
import type { Provider, OnApplicationShutdown } from '@nestjs/common';
|
import type { Provider, OnApplicationShutdown } from '@nestjs/common';
|
||||||
|
|
||||||
const config = loadConfig();
|
|
||||||
|
|
||||||
const $config: Provider = {
|
const $config: Provider = {
|
||||||
provide: DI.config,
|
provide: DI.config,
|
||||||
useValue: config,
|
useValue: loadConfig(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const $db: Provider = {
|
const $db: Provider = {
|
||||||
|
@ -28,18 +25,31 @@ const $db: Provider = {
|
||||||
const $redis: Provider = {
|
const $redis: Provider = {
|
||||||
provide: DI.redis,
|
provide: DI.redis,
|
||||||
useFactory: (config) => {
|
useFactory: (config) => {
|
||||||
const redisClient = createRedisConnection(config);
|
return new Redis({
|
||||||
return redisClient;
|
port: config.redis.port,
|
||||||
|
host: config.redis.host,
|
||||||
|
family: config.redis.family == null ? 0 : config.redis.family,
|
||||||
|
password: config.redis.pass,
|
||||||
|
keyPrefix: `${config.redis.prefix}:`,
|
||||||
|
db: config.redis.db ?? 0,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
const $redisSubscriber: Provider = {
|
const $redisForPubsub: Provider = {
|
||||||
provide: DI.redisSubscriber,
|
provide: DI.redisForPubsub,
|
||||||
useFactory: (config) => {
|
useFactory: (config) => {
|
||||||
const redisSubscriber = createRedisConnection(config);
|
const redis = new Redis({
|
||||||
redisSubscriber.subscribe(config.host);
|
port: config.redisForPubsub.port,
|
||||||
return redisSubscriber;
|
host: config.redisForPubsub.host,
|
||||||
|
family: config.redisForPubsub.family == null ? 0 : config.redisForPubsub.family,
|
||||||
|
password: config.redisForPubsub.pass,
|
||||||
|
keyPrefix: `${config.redisForPubsub.prefix}:`,
|
||||||
|
db: config.redisForPubsub.db ?? 0,
|
||||||
|
});
|
||||||
|
redis.subscribe(config.host);
|
||||||
|
return redis;
|
||||||
},
|
},
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
@ -47,14 +57,14 @@ const $redisSubscriber: Provider = {
|
||||||
@Global()
|
@Global()
|
||||||
@Module({
|
@Module({
|
||||||
imports: [RepositoryModule],
|
imports: [RepositoryModule],
|
||||||
providers: [$config, $db, $redis, $redisSubscriber],
|
providers: [$config, $db, $redis, $redisForPubsub],
|
||||||
exports: [$config, $db, $redis, $redisSubscriber, RepositoryModule],
|
exports: [$config, $db, $redis, $redisForPubsub, RepositoryModule],
|
||||||
})
|
})
|
||||||
export class GlobalModule implements OnApplicationShutdown {
|
export class GlobalModule implements OnApplicationShutdown {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.db) private db: DataSource,
|
@Inject(DI.db) private db: DataSource,
|
||||||
@Inject(DI.redis) private redisClient: Redis.Redis,
|
@Inject(DI.redis) private redisClient: Redis.Redis,
|
||||||
@Inject(DI.redisSubscriber) private redisSubscriber: Redis.Redis,
|
@Inject(DI.redisForPubsub) private redisForPubsub: Redis.Redis,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async onApplicationShutdown(signal: string): Promise<void> {
|
async onApplicationShutdown(signal: string): Promise<void> {
|
||||||
|
@ -69,7 +79,7 @@ export class GlobalModule implements OnApplicationShutdown {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.db.destroy(),
|
this.db.destroy(),
|
||||||
this.redisClient.disconnect(),
|
this.redisClient.disconnect(),
|
||||||
this.redisSubscriber.disconnect(),
|
this.redisForPubsub.disconnect(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,14 @@ export type Source = {
|
||||||
db?: number;
|
db?: number;
|
||||||
prefix?: string;
|
prefix?: string;
|
||||||
};
|
};
|
||||||
|
redisForPubsub?: {
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
family?: number;
|
||||||
|
pass: string;
|
||||||
|
db?: number;
|
||||||
|
prefix?: string;
|
||||||
|
};
|
||||||
elasticsearch: {
|
elasticsearch: {
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
@ -151,6 +159,7 @@ export function loadConfig() {
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!config.redis.prefix) config.redis.prefix = mixin.host;
|
if (!config.redis.prefix) config.redis.prefix = mixin.host;
|
||||||
|
if (config.redisForPubsub == null) config.redisForPubsub = config.redis;
|
||||||
|
|
||||||
return Object.assign(config, mixin);
|
return Object.assign(config, mixin);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
@Inject(DI.redis)
|
@Inject(DI.redis)
|
||||||
private redisClient: Redis.Redis,
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.redisSubscriber)
|
@Inject(DI.redisForPubsub)
|
||||||
private redisSubscriber: Redis.Redis,
|
private redisForPubsub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.mutingsRepository)
|
@Inject(DI.mutingsRepository)
|
||||||
private mutingsRepository: MutingsRepository,
|
private mutingsRepository: MutingsRepository,
|
||||||
|
@ -52,12 +52,12 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
this.antennasFetched = false;
|
this.antennasFetched = false;
|
||||||
this.antennas = [];
|
this.antennas = [];
|
||||||
|
|
||||||
this.redisSubscriber.on('message', this.onRedisMessage);
|
this.redisForPubsub.on('message', this.onRedisMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
this.redisSubscriber.off('message', this.onRedisMessage);
|
this.redisForPubsub.off('message', this.onRedisMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -14,8 +14,8 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
private intervalId: NodeJS.Timer;
|
private intervalId: NodeJS.Timer;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.redisSubscriber)
|
@Inject(DI.redisForPubsub)
|
||||||
private redisSubscriber: Redis.Redis,
|
private redisForPubsub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.db)
|
@Inject(DI.db)
|
||||||
private db: DataSource,
|
private db: DataSource,
|
||||||
|
@ -33,7 +33,7 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
}, 1000 * 60 * 5);
|
}, 1000 * 60 * 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.redisSubscriber.on('message', this.onMessage);
|
this.redisForPubsub.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -122,6 +122,6 @@ export class MetaService implements OnApplicationShutdown {
|
||||||
@bindThis
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
clearInterval(this.intervalId);
|
clearInterval(this.intervalId);
|
||||||
this.redisSubscriber.off('message', this.onMessage);
|
this.redisForPubsub.off('message', this.onMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,8 +64,8 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
public static NotAssignedError = class extends Error {};
|
public static NotAssignedError = class extends Error {};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.redisSubscriber)
|
@Inject(DI.redisForPubsub)
|
||||||
private redisSubscriber: Redis.Redis,
|
private redisForPubsub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
@ -87,7 +87,7 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
this.rolesCache = new MemorySingleCache<Role[]>(Infinity);
|
this.rolesCache = new MemorySingleCache<Role[]>(Infinity);
|
||||||
this.roleAssignmentByUserIdCache = new MemoryKVCache<RoleAssignment[]>(Infinity);
|
this.roleAssignmentByUserIdCache = new MemoryKVCache<RoleAssignment[]>(Infinity);
|
||||||
|
|
||||||
this.redisSubscriber.on('message', this.onMessage);
|
this.redisForPubsub.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -400,6 +400,6 @@ export class RoleService implements OnApplicationShutdown {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
this.redisSubscriber.off('message', this.onMessage);
|
this.redisForPubsub.off('message', this.onMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,14 +13,14 @@ export class WebhookService implements OnApplicationShutdown {
|
||||||
private webhooks: Webhook[] = [];
|
private webhooks: Webhook[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.redisSubscriber)
|
@Inject(DI.redisForPubsub)
|
||||||
private redisSubscriber: Redis.Redis,
|
private redisForPubsub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.webhooksRepository)
|
@Inject(DI.webhooksRepository)
|
||||||
private webhooksRepository: WebhooksRepository,
|
private webhooksRepository: WebhooksRepository,
|
||||||
) {
|
) {
|
||||||
//this.onMessage = this.onMessage.bind(this);
|
//this.onMessage = this.onMessage.bind(this);
|
||||||
this.redisSubscriber.on('message', this.onMessage);
|
this.redisForPubsub.on('message', this.onMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -82,6 +82,6 @@ export class WebhookService implements OnApplicationShutdown {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public onApplicationShutdown(signal?: string | undefined) {
|
public onApplicationShutdown(signal?: string | undefined) {
|
||||||
this.redisSubscriber.off('message', this.onMessage);
|
this.redisForPubsub.off('message', this.onMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ export const DI = {
|
||||||
config: Symbol('config'),
|
config: Symbol('config'),
|
||||||
db: Symbol('db'),
|
db: Symbol('db'),
|
||||||
redis: Symbol('redis'),
|
redis: Symbol('redis'),
|
||||||
redisSubscriber: Symbol('redisSubscriber'),
|
redisForPubsub: Symbol('redisForPubsub'),
|
||||||
|
|
||||||
//#region Repositories
|
//#region Repositories
|
||||||
usersRepository: Symbol('usersRepository'),
|
usersRepository: Symbol('usersRepository'),
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import Redis from 'ioredis';
|
|
||||||
import { Config } from '@/config.js';
|
|
||||||
|
|
||||||
export function createRedisConnection(config: Config): Redis.Redis {
|
|
||||||
return new Redis({
|
|
||||||
port: config.redis.port,
|
|
||||||
host: config.redis.host,
|
|
||||||
family: config.redis.family == null ? 0 : config.redis.family,
|
|
||||||
password: config.redis.pass,
|
|
||||||
keyPrefix: `${config.redis.prefix}:`,
|
|
||||||
db: config.redis.db ?? 0,
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -22,8 +22,8 @@ export class StreamingApiServerService {
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
|
||||||
@Inject(DI.redisSubscriber)
|
@Inject(DI.redisForPubsub)
|
||||||
private redisSubscriber: Redis.Redis,
|
private redisForPubsub: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
@ -81,7 +81,7 @@ export class StreamingApiServerService {
|
||||||
ev.emit(parsed.channel, parsed.message);
|
ev.emit(parsed.channel, parsed.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.redisSubscriber.on('message', onRedisMessage);
|
this.redisForPubsub.on('message', onRedisMessage);
|
||||||
|
|
||||||
const main = new MainStreamConnection(
|
const main = new MainStreamConnection(
|
||||||
this.channelsService,
|
this.channelsService,
|
||||||
|
@ -111,7 +111,7 @@ export class StreamingApiServerService {
|
||||||
connection.once('close', () => {
|
connection.once('close', () => {
|
||||||
ev.removeAllListeners();
|
ev.removeAllListeners();
|
||||||
main.dispose();
|
main.dispose();
|
||||||
this.redisSubscriber.off('message', onRedisMessage);
|
this.redisForPubsub.off('message', onRedisMessage);
|
||||||
if (intervalId) clearInterval(intervalId);
|
if (intervalId) clearInterval(intervalId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue