From fa871a5654fcf60786496c267fbdbd2e27e0b9c0 Mon Sep 17 00:00:00 2001 From: happy-juny <38745815+Istiopaxx@users.noreply.github.com> Date: Sat, 18 Nov 2023 02:17:59 +0900 Subject: [PATCH] [Fix]: mongodb write conflict on multi-doc transaction (#101) * omit mongo transactional * add timestamp for logs * divide view recipe * fix pm2 cluster instance * reset dividing view recipe --- api/ecosystem.config.js | 3 ++- api/libs/auth/src/services/auth.service.ts | 6 ------ api/libs/common/src/crud.service.ts | 6 ------ api/libs/common/src/log/log.decorator.ts | 10 ++++++---- .../src/services/user-ingredient.service.ts | 7 ------- api/libs/recipe/src/services/recipe.service.ts | 12 ++---------- api/libs/user/src/services/user.service.ts | 7 ------- 7 files changed, 10 insertions(+), 41 deletions(-) diff --git a/api/ecosystem.config.js b/api/ecosystem.config.js index e8e6801..77a2788 100644 --- a/api/ecosystem.config.js +++ b/api/ecosystem.config.js @@ -1,8 +1,9 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ module.exports = [ { name: 'app', script: 'main.js', exec_mode: 'cluster', - instances: 'max', + instances: Math.max(require('os').cpus().length - 1, 1), // CPU 코어 수에서 1를 뺀 값 }, ]; diff --git a/api/libs/auth/src/services/auth.service.ts b/api/libs/auth/src/services/auth.service.ts index 9f41739..82874d5 100644 --- a/api/libs/auth/src/services/auth.service.ts +++ b/api/libs/auth/src/services/auth.service.ts @@ -14,7 +14,6 @@ import { UserInfo } from '../types/user-info.type'; import { LoginSessionDto } from '../dto/token.dto'; import { v4 as uuidv4 } from 'uuid'; import { Logable } from '@app/common/log/log.decorator'; -import { MongoTransactional } from '@app/common/transaction/mongo-transaction.service'; @Injectable() export class AuthService { @@ -26,7 +25,6 @@ export class AuthService { ) {} @Logable() - @MongoTransactional() async register(createUserDto: CreateUserDto): Promise { const user = await this.userService.create(createUserDto); return await this.login(user); @@ -39,7 +37,6 @@ export class AuthService { } @Logable() - @MongoTransactional({ readOnly: true }) async findBySessionToken(sessionToken: string) { const ret = await this.authRepository.findBySessionToken(sessionToken); if (!ret) { @@ -49,7 +46,6 @@ export class AuthService { } @Logable() - @MongoTransactional() async login(user: User): Promise { const session_token = uuidv4(); await this.authRepository.create({ @@ -63,7 +59,6 @@ export class AuthService { } @Logable() - @MongoTransactional() async OAuthLoginByEmail(userInfo: UserInfo): Promise { const { email, username } = userInfo; const user = await this.userService.findByEmail(email); @@ -111,7 +106,6 @@ export class AuthService { } @Logable() - @MongoTransactional() async logout(sessionToken: string) { await this.authRepository.deleteBySessionToken(sessionToken); } diff --git a/api/libs/common/src/crud.service.ts b/api/libs/common/src/crud.service.ts index d20bb51..00d2613 100644 --- a/api/libs/common/src/crud.service.ts +++ b/api/libs/common/src/crud.service.ts @@ -1,6 +1,5 @@ import { NotFoundException } from '@nestjs/common'; import { ICrudRepository } from './crud.repository'; -import { MongoTransactional } from './transaction/mongo-transaction.service'; export class CrudService { private repository: ICrudRepository; @@ -10,17 +9,14 @@ export class CrudService { this.repository = repository; } - @MongoTransactional() async create(createDto: CreateDto): Promise { return await this.repository.create(createDto); } - @MongoTransactional({ readOnly: true }) async findAll(filterDto: FilterDto): Promise { return await this.repository.findAll(filterDto); } - @MongoTransactional({ readOnly: true }) async findOne(id: string): Promise { const ret = await this.repository.findOne(id); if (!ret) { @@ -29,7 +25,6 @@ export class CrudService { return ret; } - @MongoTransactional() async update(id: string, updateDto: UpdateDto): Promise { const ret = await this.repository.update(id, updateDto); if (!ret) { @@ -38,7 +33,6 @@ export class CrudService { return ret; } - @MongoTransactional() async deleteOne(id: string): Promise { const ret = await this.repository.deleteOne(id); if (!ret) { diff --git a/api/libs/common/src/log/log.decorator.ts b/api/libs/common/src/log/log.decorator.ts index 1606790..a64a106 100644 --- a/api/libs/common/src/log/log.decorator.ts +++ b/api/libs/common/src/log/log.decorator.ts @@ -21,14 +21,16 @@ export class LogDecorator implements LazyDecorator { const t = Date.now(); const ret = await method(...args); console.log( - `[${reqId}] ${instance.constructor.name}.${methodName} executed in ${ - Date.now() - t - }ms`, + `[${reqId}] [${new Date().toISOString()}] ${ + instance.constructor.name + }.${methodName} executed in ${Date.now() - t}ms`, ); return ret; } catch (e) { console.error( - `[${reqId}] ${instance.constructor.name}.${methodName} error: ${e}`, + `[${reqId}] [${new Date().toISOString()}] ${ + instance.constructor.name + }.${methodName} error: ${e}`, ); throw e; } diff --git a/api/libs/ingredient/src/services/user-ingredient.service.ts b/api/libs/ingredient/src/services/user-ingredient.service.ts index 370055a..80472d5 100644 --- a/api/libs/ingredient/src/services/user-ingredient.service.ts +++ b/api/libs/ingredient/src/services/user-ingredient.service.ts @@ -16,7 +16,6 @@ import { } from '../dto/modify-ingredient.dto'; import { UserIngredient } from '../entities/user-ingredient.entity'; import { UserIngredientRepository } from '../repositories/user-ingredient.repository'; -import { MongoTransactional } from '@app/common/transaction/mongo-transaction.service'; interface ImageProcessService { getBarcodeInfoFromUrl( @@ -57,28 +56,24 @@ export class UserIngredientService implements OnModuleInit { return ret; } - @MongoTransactional() async create( createUserIngredientDto: CreateUserIngredientDto, ): Promise { return await this.userIngredientRepository.create(createUserIngredientDto); } - @MongoTransactional({ readOnly: true }) async findAll( filterUserIngredientDto: FilterUserIngredientDto, ): Promise { return await this.userIngredientRepository.findAll(filterUserIngredientDto); } - @MongoTransactional({ readOnly: true }) async findOne(id: string): Promise { const ret = await this.userIngredientRepository.findOne(id); if (!ret) throw new NotFoundException('UserIngredient not found'); return ret; } - @MongoTransactional() async update( id: string, updateUserIngredientDto: UpdateUserIngredientDto, @@ -91,14 +86,12 @@ export class UserIngredientService implements OnModuleInit { return ret; } - @MongoTransactional() async deleteOne(id: string): Promise { const ret = await this.userIngredientRepository.deleteOne(id); if (!ret) throw new NotFoundException('UserIngredient not found'); return ret; } - @MongoTransactional() async deleteAll( filterUserIngredientDto: FilterUserIngredientDto, ): Promise { diff --git a/api/libs/recipe/src/services/recipe.service.ts b/api/libs/recipe/src/services/recipe.service.ts index 231ffdd..c312328 100644 --- a/api/libs/recipe/src/services/recipe.service.ts +++ b/api/libs/recipe/src/services/recipe.service.ts @@ -18,10 +18,9 @@ import { import { Recipe } from '../entities/recipe.entity'; import { RecipeRepository } from '../repositories/recipe.repository'; import { RecipeViewerIdentifier } from '../dto/recipe-view-log/recipe-viewer-identifier'; -import { MemoryCacheable } from '@app/common/cache/memory-cache.service'; import { Logable } from '@app/common/log/log.decorator'; import { RecipeViewLogRepository } from '../repositories/recipe-view-log.repository'; -import { MongoTransactional } from '@app/common/transaction/mongo-transaction.service'; +import { Cacheable } from '@app/common/cache/cache.service'; @Injectable() export class RecipeService implements OnApplicationBootstrap { @@ -31,13 +30,11 @@ export class RecipeService implements OnApplicationBootstrap { ) {} @Logable() - @MongoTransactional() async create(createRecipeDto: CreateRecipeDto): Promise { return await this.recipeRepository.create(createRecipeDto); } @Logable() - @MongoTransactional({ readOnly: true }) async findAll(filterRecipeDto: FilterRecipeDto): Promise { const { page, limit } = filterRecipeDto; const results = await this.recipeRepository.findAll(filterRecipeDto); @@ -45,7 +42,6 @@ export class RecipeService implements OnApplicationBootstrap { } @Logable() - @MongoTransactional({ readOnly: true }) async findAllByFullTextSearch( textSearchRecipeDto: TextSearchRecipeDto, ): Promise { @@ -66,7 +62,6 @@ export class RecipeService implements OnApplicationBootstrap { } @Logable() - @MongoTransactional() async findOne( id: string, identifier: RecipeViewerIdentifier, @@ -82,14 +77,12 @@ export class RecipeService implements OnApplicationBootstrap { } @Logable() - @MongoTransactional({ readOnly: true }) async findTopViewed(): Promise { return await this.recipeViewLogRepository.findAll5MostViewedRecipesInPast1Month(); } @Logable() - @MongoTransactional() - @MemoryCacheable({ + @Cacheable({ ttl: 60 * 60 * 1000, keyGenerator: (id: string, identifier: RecipeViewerIdentifier) => identifier.user @@ -118,7 +111,6 @@ export class RecipeService implements OnApplicationBootstrap { } @Logable() - @MongoTransactional() async update(id: string, updateRecipeDto: UpdateRecipeDto): Promise { const ret = await this.recipeRepository.update(id, updateRecipeDto); if (!ret) throw new NotFoundException('Recipe not found'); diff --git a/api/libs/user/src/services/user.service.ts b/api/libs/user/src/services/user.service.ts index a9ddd0a..9de66fc 100644 --- a/api/libs/user/src/services/user.service.ts +++ b/api/libs/user/src/services/user.service.ts @@ -8,14 +8,12 @@ import { FilterUserDto } from '../dto/filter-user.dto'; import { User } from '../entities/user.entity'; import { UserRepository } from '../repositories/user.repository'; import { Logable } from '@app/common/log/log.decorator'; -import { MongoTransactional } from '@app/common/transaction/mongo-transaction.service'; @Injectable() export class UserService { constructor(private readonly userRepository: UserRepository) {} @Logable() - @MongoTransactional() async create(createUserDto: CreateUserDto): Promise { const { email, username } = createUserDto; const [dupEmail, dupUsername] = await Promise.all([ @@ -29,13 +27,11 @@ export class UserService { } @Logable() - @MongoTransactional({ readOnly: true }) async findAll(filterDto: any): Promise { return await this.userRepository.findAll(filterDto); } @Logable() - @MongoTransactional({ readOnly: true }) async findOne(id: string): Promise { const ret = await this.userRepository.findOne(id); if (!ret) { @@ -45,13 +41,11 @@ export class UserService { } @Logable() - @MongoTransactional({ readOnly: true }) async findByEmail(email: string): Promise { return await this.userRepository.findByEmail(email); } @Logable() - @MongoTransactional() async update(id: string, updateDto: UpdateUserDto): Promise { const { username } = updateDto; const dupUsername = await this.userRepository.findByUsername(username); @@ -66,7 +60,6 @@ export class UserService { } @Logable() - @MongoTransactional() async deleteOne(id: string): Promise { const ret = await this.userRepository.deleteOne(id); if (!ret) {