Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve tl performance #11946

Merged
merged 51 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
06cfe61
wip
syuilo Oct 1, 2023
3dd3c69
wip
syuilo Oct 1, 2023
783a97f
wip
syuilo Oct 1, 2023
72f7413
wip
syuilo Oct 1, 2023
167aaab
wip
syuilo Oct 1, 2023
c019e9c
wip
syuilo Oct 1, 2023
f0a2c3c
Update NoteCreateService.ts
syuilo Oct 1, 2023
85430fd
wip
syuilo Oct 1, 2023
7f4c005
wip
syuilo Oct 1, 2023
d9aac11
wip
syuilo Oct 1, 2023
3924a9e
wip
syuilo Oct 1, 2023
b4c1de1
Update NoteCreateService.ts
syuilo Oct 2, 2023
cb821d4
wip
syuilo Oct 2, 2023
0db117b
Update NoteCreateService.ts
syuilo Oct 2, 2023
e4de402
wip
syuilo Oct 2, 2023
6f17993
Update user-notes.ts
syuilo Oct 2, 2023
35e743c
wip
syuilo Oct 2, 2023
caca0da
wip
syuilo Oct 2, 2023
79e5075
wip
syuilo Oct 2, 2023
c7c4c78
Update NoteCreateService.ts
syuilo Oct 2, 2023
8843669
wip
syuilo Oct 2, 2023
d40f35b
Update timeline.ts
syuilo Oct 2, 2023
55e5056
Update timeline.ts
syuilo Oct 2, 2023
880448d
Update timeline.ts
syuilo Oct 2, 2023
bbcda73
Update timeline.ts
syuilo Oct 3, 2023
58d2512
Update timeline.ts
syuilo Oct 3, 2023
152047c
wip
syuilo Oct 3, 2023
2f00e4b
Update timelines.ts
syuilo Oct 3, 2023
aad48b4
Update timelines.ts
syuilo Oct 3, 2023
d6ff810
Update timelines.ts
syuilo Oct 3, 2023
ea0d050
wip
syuilo Oct 3, 2023
6d68cfd
wip
syuilo Oct 3, 2023
236eed9
wip
syuilo Oct 3, 2023
0e302c6
Update timelines.ts
syuilo Oct 3, 2023
15caa37
Update misskey-js.api.md
syuilo Oct 3, 2023
72d5b1f
Update timelines.ts
syuilo Oct 3, 2023
b66df85
Update timelines.ts
syuilo Oct 3, 2023
58eec94
wip
syuilo Oct 3, 2023
45c3ab2
wip
syuilo Oct 3, 2023
96da6e2
wip
syuilo Oct 3, 2023
878e73c
Update timelines.ts
syuilo Oct 3, 2023
ee3d40b
wip
syuilo Oct 3, 2023
7022b16
Update timelines.ts
syuilo Oct 3, 2023
e12943c
wip
syuilo Oct 3, 2023
9de11da
Merge branch 'develop' into tl-push
syuilo Oct 3, 2023
c3714c0
test
syuilo Oct 3, 2023
0e58f51
Update activitypub.ts
syuilo Oct 3, 2023
e840544
refactor: UserListJoining -> UserListMembership
syuilo Oct 3, 2023
7a3dd40
Update NoteCreateService.ts
syuilo Oct 3, 2023
0575207
Merge branch 'develop' into tl-push
syuilo Oct 3, 2023
77498f8
wip
syuilo Oct 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .config/docker_example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ redis:
# #prefix: example-prefix
# #db: 1

#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1

# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────

Expand Down
10 changes: 10 additions & 0 deletions .config/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ redis:
# # You can specify more ioredis options...
# #username: example-username

#redisForTimelines:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username

# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────

Expand Down
8 changes: 8 additions & 0 deletions .devcontainer/devcontainer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ redis:
# #prefix: example-prefix
# #db: 1

#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1

# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────

Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,24 @@
-->

## 2023.10.0
### NOTE
- muted_noteテーブルは使われなくなったため手動で削除を行ってください。

### Changes
- API: users/notes, notes/local-timeline で fileType 指定はできなくなりました
- API: notes/global-timeline は現在常に `[]` を返します

### General
- ユーザーごとに他ユーザーへの返信をタイムラインに含めるか設定可能になりました
- ユーザーリスト内のメンバーごとに他ユーザーへの返信をユーザーリストタイムラインに含めるか設定可能になりました
- ソフトワードミュートとハードワードミュートは統合されました

### Client
- Fix: リアクションしたユーザ一覧のUIが稀に左上に残ってしまう不具合を修正

### Server
- タイムライン取得時のパフォーマンスを改善

## 2023.9.3
### General
- Enhance: ノートの翻訳機能の利用可否をロールで設定可能に
Expand Down
8 changes: 8 additions & 0 deletions chart/files/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ redis:
# #prefix: example-prefix
# #db: 1

#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1

# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────

Expand Down
7 changes: 2 additions & 5 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,8 @@ export interface Locale {
"notificationRecieveConfig": string;
"mutualFollow": string;
"fileAttachedOnly": string;
"showRepliesToOthersInTimeline": string;
"hideRepliesToOthersInTimeline": string;
"_announcement": {
"forExistingUsers": string;
"forExistingUsersDescription": string;
Expand Down Expand Up @@ -1719,11 +1721,6 @@ export interface Locale {
"muteWords": string;
"muteWordsDescription": string;
"muteWordsDescription2": string;
"softDescription": string;
"hardDescription": string;
"soft": string;
"hard": string;
"mutedNotes": string;
};
"_instanceMute": {
"instanceMuteDescription": string;
Expand Down
7 changes: 2 additions & 5 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,8 @@ edited: "編集済み"
notificationRecieveConfig: "通知の受信設定"
mutualFollow: "相互フォロー"
fileAttachedOnly: "ファイル付きのみ"
showRepliesToOthersInTimeline: "TLに他の人への返信を含める"
hideRepliesToOthersInTimeline: "TLに他の人への返信を含めない"

_announcement:
forExistingUsers: "既存ユーザーのみ"
Expand Down Expand Up @@ -1636,11 +1638,6 @@ _wordMute:
muteWords: "ミュートするワード"
muteWordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります。"
muteWordsDescription2: "キーワードをスラッシュで囲むと正規表現になります。"
softDescription: "指定した条件のノートをタイムラインから隠します。"
hardDescription: "指定した条件のノートをタイムラインに追加しないようにします。追加されなかったノートは、条件を変更しても除外されたままになります。"
soft: "ソフト"
hard: "ハード"
mutedNotes: "ミュートされたノート"

_instanceMute:
instanceMuteDescription: "ミュートしたサーバーのユーザーへの返信を含めて、設定したサーバーの全てのノートとRenoteをミュートします。"
Expand Down
2 changes: 2 additions & 0 deletions packages/backend/jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,6 @@ module.exports = {
maxWorkers: 1, // Make it use worker (that can be killed and restarted)
logHeapUsage: true, // To debug when out-of-memory happens on CI
workerIdleMemoryLimit: '1GiB', // Limit the worker to 1GB (GitHub Workflows dies at 2GB)

maxConcurrency: 32,
};
20 changes: 20 additions & 0 deletions packages/backend/migration/1696222183852-withReplies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

export class WithReplies1696222183852 {
name = 'WithReplies1696222183852'

async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "following" ADD "withReplies" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "user_list_joining" ADD "withReplies" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`CREATE INDEX "IDX_d74d8ab5efa7e3bb82825c0fa2" ON "following" ("followeeId", "followerHost") `);
}

async down(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_d74d8ab5efa7e3bb82825c0fa2"`);
await queryRunner.query(`ALTER TABLE "user_list_joining" DROP COLUMN "withReplies"`);
await queryRunner.query(`ALTER TABLE "following" DROP COLUMN "withReplies"`);
}
}
11 changes: 11 additions & 0 deletions packages/backend/migration/1696323464251-user-list-membership.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class UserListMembership1696323464251 {
name = 'UserListMembership1696323464251'

async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_list_joining" RENAME TO "user_list_membership"`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_list_membership" RENAME TO "user_list_joining"`);
}
}
17 changes: 17 additions & 0 deletions packages/backend/migration/1696331570827-hibernation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export class Hibernation1696331570827 {
name = 'Hibernation1696331570827'

async up(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_d74d8ab5efa7e3bb82825c0fa2"`);
await queryRunner.query(`ALTER TABLE "user" ADD "isHibernated" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "following" ADD "isFollowerHibernated" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`CREATE INDEX "IDX_ce62b50d882d4e9dee10ad0d2f" ON "following" ("followeeId", "followerHost", "isFollowerHibernated") `);
}

async down(queryRunner) {
await queryRunner.query(`DROP INDEX "public"."IDX_ce62b50d882d4e9dee10ad0d2f"`);
await queryRunner.query(`ALTER TABLE "following" DROP COLUMN "isFollowerHibernated"`);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isHibernated"`);
await queryRunner.query(`CREATE INDEX "IDX_d74d8ab5efa7e3bb82825c0fa2" ON "following" ("followeeId", "followerHost") `);
}
}
14 changes: 12 additions & 2 deletions packages/backend/src/GlobalModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,27 @@ const $redisForSub: Provider = {
inject: [DI.config],
};

const $redisForTimelines: Provider = {
provide: DI.redisForTimelines,
useFactory: (config: Config) => {
return new Redis.Redis(config.redisForTimelines);
},
inject: [DI.config],
};

@Global()
@Module({
imports: [RepositoryModule],
providers: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub],
exports: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, RepositoryModule],
providers: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines],
exports: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, RepositoryModule],
})
export class GlobalModule implements OnApplicationShutdown {
constructor(
@Inject(DI.db) private db: DataSource,
@Inject(DI.redis) private redisClient: Redis.Redis,
@Inject(DI.redisForPub) private redisForPub: Redis.Redis,
@Inject(DI.redisForSub) private redisForSub: Redis.Redis,
@Inject(DI.redisForTimelines) private redisForTimelines: Redis.Redis,
) {}

public async dispose(): Promise<void> {
Expand All @@ -98,6 +107,7 @@ export class GlobalModule implements OnApplicationShutdown {
this.redisClient.disconnect(),
this.redisForPub.disconnect(),
this.redisForSub.disconnect(),
this.redisForTimelines.disconnect(),
]);
}

Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type Source = {
redis: RedisOptionsSource;
redisForPubsub?: RedisOptionsSource;
redisForJobQueue?: RedisOptionsSource;
redisForTimelines?: RedisOptionsSource;
meilisearch?: {
host: string;
port: string;
Expand Down Expand Up @@ -161,6 +162,7 @@ export type Config = {
redis: RedisOptions & RedisOptionsSource;
redisForPubsub: RedisOptions & RedisOptionsSource;
redisForJobQueue: RedisOptions & RedisOptionsSource;
redisForTimelines: RedisOptions & RedisOptionsSource;
perChannelMaxNoteCacheCount: number;
perUserNotificationsMaxCount: number;
deactivateAntennaThreshold: number;
Expand Down Expand Up @@ -227,6 +229,7 @@ export function loadConfig(): Config {
redis,
redisForPubsub: config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, host) : redis,
redisForJobQueue: config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, host) : redis,
redisForTimelines: config.redisForTimelines ? convertRedisOptions(config.redisForTimelines, host) : redis,
id: config.id,
proxy: config.proxy,
proxySmtp: config.proxySmtp,
Expand Down
30 changes: 15 additions & 15 deletions packages/backend/src/core/AccountMoveService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js';
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MutingsRepository, UserListJoiningsRepository, UsersRepository } from '@/models/_.js';
import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MutingsRepository, UserListMembershipsRepository, UsersRepository } from '@/models/_.js';
import type { RelationshipJobData, ThinUser } from '@/queue/types.js';

import { IdService } from '@/core/IdService.js';
Expand Down Expand Up @@ -42,8 +42,8 @@ export class AccountMoveService {
@Inject(DI.mutingsRepository)
private mutingsRepository: MutingsRepository,

@Inject(DI.userListJoiningsRepository)
private userListJoiningsRepository: UserListJoiningsRepository,
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,

@Inject(DI.instancesRepository)
private instancesRepository: InstancesRepository,
Expand Down Expand Up @@ -215,40 +215,40 @@ export class AccountMoveService {
@bindThis
public async updateLists(src: ThinUser, dst: MiUser): Promise<void> {
// Return if there is no list to be updated.
const oldJoinings = await this.userListJoiningsRepository.find({
const oldMemberships = await this.userListMembershipsRepository.find({
where: {
userId: src.id,
},
});
if (oldJoinings.length === 0) return;
if (oldMemberships.length === 0) return;

const existingUserListIds = await this.userListJoiningsRepository.find({
const existingUserListIds = await this.userListMembershipsRepository.find({
where: {
userId: dst.id,
},
}).then(joinings => joinings.map(joining => joining.userListId));
}).then(memberships => memberships.map(membership => membership.userListId));

const newJoinings: Map<string, { createdAt: Date; userId: string; userListId: string; }> = new Map();
const newMemberships: Map<string, { createdAt: Date; userId: string; userListId: string; }> = new Map();

// 重複しないようにIDを生成
const genId = (): string => {
let id: string;
do {
id = this.idService.genId();
} while (newJoinings.has(id));
} while (newMemberships.has(id));
return id;
};
for (const joining of oldJoinings) {
if (existingUserListIds.includes(joining.userListId)) continue; // skip if dst exists in this user's list
newJoinings.set(genId(), {
for (const membership of oldMemberships) {
if (existingUserListIds.includes(membership.userListId)) continue; // skip if dst exists in this user's list
newMemberships.set(genId(), {
createdAt: new Date(),
userId: dst.id,
userListId: joining.userListId,
userListId: membership.userListId,
});
}

const arrayToInsert = Array.from(newJoinings.entries()).map(entry => ({ ...entry[1], id: entry[0] }));
await this.userListJoiningsRepository.insert(arrayToInsert);
const arrayToInsert = Array.from(newMemberships.entries()).map(entry => ({ ...entry[1], id: entry[0] }));
await this.userListMembershipsRepository.insert(arrayToInsert);

// Have the proxy account follow the new account in the same way as UserListService.push
if (this.userEntityService.isRemoteUser(dst)) {
Expand Down
14 changes: 7 additions & 7 deletions packages/backend/src/core/AntennaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
import * as Acct from '@/misc/acct.js';
import type { Packed } from '@/misc/json-schema.js';
import { DI } from '@/di-symbols.js';
import type { AntennasRepository, UserListJoiningsRepository } from '@/models/_.js';
import type { AntennasRepository, UserListMembershipsRepository } from '@/models/_.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
Expand All @@ -24,17 +24,17 @@ export class AntennaService implements OnApplicationShutdown {
private antennas: MiAntenna[];

constructor(
@Inject(DI.redis)
private redisClient: Redis.Redis,
@Inject(DI.redisForTimelines)
private redisForTimelines: Redis.Redis,

@Inject(DI.redisForSub)
private redisForSub: Redis.Redis,

@Inject(DI.antennasRepository)
private antennasRepository: AntennasRepository,

@Inject(DI.userListJoiningsRepository)
private userListJoiningsRepository: UserListJoiningsRepository,
@Inject(DI.userListMembershipsRepository)
private userListMembershipsRepository: UserListMembershipsRepository,

private utilityService: UtilityService,
private globalEventService: GlobalEventService,
Expand Down Expand Up @@ -81,7 +81,7 @@ export class AntennaService implements OnApplicationShutdown {
const antennasWithMatchResult = await Promise.all(antennas.map(antenna => this.checkHitAntenna(antenna, note, noteUser).then(hit => [antenna, hit] as const)));
const matchedAntennas = antennasWithMatchResult.filter(([, hit]) => hit).map(([antenna]) => antenna);

const redisPipeline = this.redisClient.pipeline();
const redisPipeline = this.redisForTimelines.pipeline();

for (const antenna of matchedAntennas) {
redisPipeline.xadd(
Expand All @@ -108,7 +108,7 @@ export class AntennaService implements OnApplicationShutdown {
if (antenna.src === 'home') {
// TODO
} else if (antenna.src === 'list') {
const listUsers = (await this.userListJoiningsRepository.findBy({
const listUsers = (await this.userListMembershipsRepository.findBy({
userListId: antenna.userListId!,
})).map(x => x.userId);

Expand Down
Loading
Loading