perf(backend): createPersonでキャッシュを積極的に利用する, トランザクション回数を減らす

This commit is contained in:
tamaina 2023-07-19 06:39:39 +00:00
parent ad9bb773c5
commit 05042a0697

View file

@ -43,6 +43,7 @@ import type { ApLoggerService } from '../ApLoggerService.js';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports // eslint-disable-next-line @typescript-eslint/consistent-type-imports
import type { ApImageService } from './ApImageService.js'; import type { ApImageService } from './ApImageService.js';
import type { IActor, IObject } from '../type.js'; import type { IActor, IObject } from '../type.js';
import { ca } from 'date-fns/locale';
const nameLength = 128; const nameLength = 128;
const summaryLength = 2048; const summaryLength = 2048;
@ -259,13 +260,49 @@ export class ApPersonService implements OnModuleInit {
// Create user // Create user
let user: RemoteUser | null = null; let user: RemoteUser | null = null;
const userAdditionalInfo: Pick<RemoteUser, 'avatarId' | 'bannerId' | 'avatarUrl' | 'bannerUrl' | 'avatarBlurhash' | 'bannerBlurhash' | 'emojis'> = {
avatarId: null,
bannerId: null,
avatarUrl: null,
bannerUrl: null,
avatarBlurhash: null,
bannerBlurhash: null,
emojis: [],
};
try {
//#region アバターとヘッダー画像をフェッチ
const [avatar, banner] = await Promise.all([person.icon, person.image].map(img => {
if (img == null) return null;
if (user == null) throw new Error('failed to create user: user is null');
return this.apImageService.resolveImage(user, img).catch(() => null);
}));
userAdditionalInfo.avatarId = avatar?.id ?? null;
userAdditionalInfo.bannerId = banner?.id ?? null;
userAdditionalInfo.avatarUrl = avatar ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null;
userAdditionalInfo.bannerUrl = banner ? this.driveFileEntityService.getPublicUrl(banner) : null;
userAdditionalInfo.avatarBlurhash = avatar?.blurhash ?? null;
userAdditionalInfo.bannerBlurhash = banner?.blurhash ?? null;
//#endregion
} catch (err) {
this.logger.error('error occured while fetching user avatar/banner', { stack: err });
}
//#region カスタム絵文字取得
userAdditionalInfo.emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host)
.then(_emojis => _emojis.map(emoji => emoji.name))
.catch(err => {
this.logger.error(`error occured while fetching user emojis`, { stack: err });
return [];
});
//#endregion
try { try {
// Start transaction // Start transaction
await this.db.transaction(async transactionalEntityManager => { await this.db.transaction(async transactionalEntityManager => {
user = await transactionalEntityManager.save(new User({ user = await transactionalEntityManager.save(new User({
id: this.idService.genId(), id: this.idService.genId(),
avatarId: null,
bannerId: null,
createdAt: new Date(), createdAt: new Date(),
lastFetchedAt: new Date(), lastFetchedAt: new Date(),
name: truncate(person.name, nameLength), name: truncate(person.name, nameLength),
@ -285,6 +322,7 @@ export class ApPersonService implements OnModuleInit {
tags, tags,
isBot, isBot,
isCat: (person as any).isCat === true, isCat: (person as any).isCat === true,
...userAdditionalInfo,
})) as RemoteUser; })) as RemoteUser;
await transactionalEntityManager.save(new UserProfile({ await transactionalEntityManager.save(new UserProfile({
@ -321,6 +359,9 @@ export class ApPersonService implements OnModuleInit {
if (user == null) throw new Error('failed to create user: user is null'); if (user == null) throw new Error('failed to create user: user is null');
// Register to the cache
this.cacheService.uriPersonCache.set(user.uri, user);
// Register host // Register host
this.federatedInstanceService.fetch(host).then(async i => { this.federatedInstanceService.fetch(host).then(async i => {
this.instancesRepository.increment({ id: i.id }, 'usersCount', 1); this.instancesRepository.increment({ id: i.id }, 'usersCount', 1);
@ -335,48 +376,6 @@ export class ApPersonService implements OnModuleInit {
// ハッシュタグ更新 // ハッシュタグ更新
this.hashtagService.updateUsertags(user, tags); this.hashtagService.updateUsertags(user, tags);
//#region アバターとヘッダー画像をフェッチ
const [avatar, banner] = await Promise.all([person.icon, person.image].map(img => {
if (img == null) return null;
if (user == null) throw new Error('failed to create user: user is null');
return this.apImageService.resolveImage(user, img).catch(() => null);
}));
const avatarId = avatar?.id ?? null;
const bannerId = banner?.id ?? null;
const avatarUrl = avatar ? this.driveFileEntityService.getPublicUrl(avatar, 'avatar') : null;
const bannerUrl = banner ? this.driveFileEntityService.getPublicUrl(banner) : null;
const avatarBlurhash = avatar?.blurhash ?? null;
const bannerBlurhash = banner?.blurhash ?? null;
await this.usersRepository.update(user.id, {
avatarId,
bannerId,
avatarUrl,
bannerUrl,
avatarBlurhash,
bannerBlurhash,
});
user.avatarId = avatarId;
user.bannerId = bannerId;
user.avatarUrl = avatarUrl;
user.bannerUrl = bannerUrl;
user.avatarBlurhash = avatarBlurhash;
user.bannerBlurhash = bannerBlurhash;
//#endregion
//#region カスタム絵文字取得
const emojis = await this.apNoteService.extractEmojis(person.tag ?? [], host).catch(err => {
this.logger.info(`extractEmojis: ${err}`);
return [];
});
const emojiNames = emojis.map(emoji => emoji.name);
await this.usersRepository.update(user.id, { emojis: emojiNames });
//#endregion
await this.updateFeatured(user.id, resolver).catch(err => this.logger.error(err)); await this.updateFeatured(user.id, resolver).catch(err => this.logger.error(err));
return user; return user;
@ -400,7 +399,7 @@ export class ApPersonService implements OnModuleInit {
if (uri.startsWith(`${this.config.url}/`)) return; if (uri.startsWith(`${this.config.url}/`)) return;
//#region このサーバーに既に登録されているか //#region このサーバーに既に登録されているか
const exist = await this.usersRepository.findOneBy({ uri }) as RemoteUser | null; const exist = await this.fetchPerson(uri) as RemoteUser | null;
if (exist === null) return; if (exist === null) return;
//#endregion //#endregion