Skip to content

Commit

Permalink
[Fix]: mongodb write conflict on multi-doc transaction (#101)
Browse files Browse the repository at this point in the history
* omit mongo transactional

* add timestamp for logs

* divide view recipe

* fix pm2 cluster instance

* reset dividing view recipe
  • Loading branch information
Istiopaxx authored Nov 17, 2023
1 parent e3342c9 commit fa871a5
Show file tree
Hide file tree
Showing 7 changed files with 10 additions and 41 deletions.
3 changes: 2 additions & 1 deletion api/ecosystem.config.js
Original file line number Diff line number Diff line change
@@ -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를 뺀 값
},
];
6 changes: 0 additions & 6 deletions api/libs/auth/src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -26,7 +25,6 @@ export class AuthService {
) {}

@Logable()
@MongoTransactional()
async register(createUserDto: CreateUserDto): Promise<LoginSessionDto> {
const user = await this.userService.create(createUserDto);
return await this.login(user);
Expand All @@ -39,7 +37,6 @@ export class AuthService {
}

@Logable()
@MongoTransactional({ readOnly: true })
async findBySessionToken(sessionToken: string) {
const ret = await this.authRepository.findBySessionToken(sessionToken);
if (!ret) {
Expand All @@ -49,7 +46,6 @@ export class AuthService {
}

@Logable()
@MongoTransactional()
async login(user: User): Promise<LoginSessionDto> {
const session_token = uuidv4();
await this.authRepository.create({
Expand All @@ -63,7 +59,6 @@ export class AuthService {
}

@Logable()
@MongoTransactional()
async OAuthLoginByEmail(userInfo: UserInfo): Promise<OAuthLoginSessionDto> {
const { email, username } = userInfo;
const user = await this.userService.findByEmail(email);
Expand Down Expand Up @@ -111,7 +106,6 @@ export class AuthService {
}

@Logable()
@MongoTransactional()
async logout(sessionToken: string) {
await this.authRepository.deleteBySessionToken(sessionToken);
}
Expand Down
6 changes: 0 additions & 6 deletions api/libs/common/src/crud.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { NotFoundException } from '@nestjs/common';
import { ICrudRepository } from './crud.repository';
import { MongoTransactional } from './transaction/mongo-transaction.service';

export class CrudService<Entity, CreateDto, UpdateDto, FilterDto> {
private repository: ICrudRepository<Entity, CreateDto, UpdateDto, FilterDto>;
Expand All @@ -10,17 +9,14 @@ export class CrudService<Entity, CreateDto, UpdateDto, FilterDto> {
this.repository = repository;
}

@MongoTransactional()
async create(createDto: CreateDto): Promise<Entity> {
return await this.repository.create(createDto);
}

@MongoTransactional({ readOnly: true })
async findAll(filterDto: FilterDto): Promise<Entity[]> {
return await this.repository.findAll(filterDto);
}

@MongoTransactional({ readOnly: true })
async findOne(id: string): Promise<Entity> {
const ret = await this.repository.findOne(id);
if (!ret) {
Expand All @@ -29,7 +25,6 @@ export class CrudService<Entity, CreateDto, UpdateDto, FilterDto> {
return ret;
}

@MongoTransactional()
async update(id: string, updateDto: UpdateDto): Promise<Entity> {
const ret = await this.repository.update(id, updateDto);
if (!ret) {
Expand All @@ -38,7 +33,6 @@ export class CrudService<Entity, CreateDto, UpdateDto, FilterDto> {
return ret;
}

@MongoTransactional()
async deleteOne(id: string): Promise<void> {
const ret = await this.repository.deleteOne(id);
if (!ret) {
Expand Down
10 changes: 6 additions & 4 deletions api/libs/common/src/log/log.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ export class LogDecorator implements LazyDecorator<any, any> {
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;
}
Expand Down
7 changes: 0 additions & 7 deletions api/libs/ingredient/src/services/user-ingredient.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -57,28 +56,24 @@ export class UserIngredientService implements OnModuleInit {
return ret;
}

@MongoTransactional()
async create(
createUserIngredientDto: CreateUserIngredientDto,
): Promise<UserIngredient> {
return await this.userIngredientRepository.create(createUserIngredientDto);
}

@MongoTransactional({ readOnly: true })
async findAll(
filterUserIngredientDto: FilterUserIngredientDto,
): Promise<UserIngredient[]> {
return await this.userIngredientRepository.findAll(filterUserIngredientDto);
}

@MongoTransactional({ readOnly: true })
async findOne(id: string): Promise<UserIngredient> {
const ret = await this.userIngredientRepository.findOne(id);
if (!ret) throw new NotFoundException('UserIngredient not found');
return ret;
}

@MongoTransactional()
async update(
id: string,
updateUserIngredientDto: UpdateUserIngredientDto,
Expand All @@ -91,14 +86,12 @@ export class UserIngredientService implements OnModuleInit {
return ret;
}

@MongoTransactional()
async deleteOne(id: string): Promise<UserIngredient> {
const ret = await this.userIngredientRepository.deleteOne(id);
if (!ret) throw new NotFoundException('UserIngredient not found');
return ret;
}

@MongoTransactional()
async deleteAll(
filterUserIngredientDto: FilterUserIngredientDto,
): Promise<any> {
Expand Down
12 changes: 2 additions & 10 deletions api/libs/recipe/src/services/recipe.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -31,21 +30,18 @@ export class RecipeService implements OnApplicationBootstrap {
) {}

@Logable()
@MongoTransactional()
async create(createRecipeDto: CreateRecipeDto): Promise<Recipe> {
return await this.recipeRepository.create(createRecipeDto);
}

@Logable()
@MongoTransactional({ readOnly: true })
async findAll(filterRecipeDto: FilterRecipeDto): Promise<RecipesResponseDto> {
const { page, limit } = filterRecipeDto;
const results = await this.recipeRepository.findAll(filterRecipeDto);
return results.toRecipesResponseDto(page, limit);
}

@Logable()
@MongoTransactional({ readOnly: true })
async findAllByFullTextSearch(
textSearchRecipeDto: TextSearchRecipeDto,
): Promise<RecipesResponseDto> {
Expand All @@ -66,7 +62,6 @@ export class RecipeService implements OnApplicationBootstrap {
}

@Logable()
@MongoTransactional()
async findOne(
id: string,
identifier: RecipeViewerIdentifier,
Expand All @@ -82,14 +77,12 @@ export class RecipeService implements OnApplicationBootstrap {
}

@Logable()
@MongoTransactional({ readOnly: true })
async findTopViewed(): Promise<RecipeListViewResponseDto[]> {
return await this.recipeViewLogRepository.findAll5MostViewedRecipesInPast1Month();
}

@Logable()
@MongoTransactional()
@MemoryCacheable({
@Cacheable({
ttl: 60 * 60 * 1000,
keyGenerator: (id: string, identifier: RecipeViewerIdentifier) =>
identifier.user
Expand Down Expand Up @@ -118,7 +111,6 @@ export class RecipeService implements OnApplicationBootstrap {
}

@Logable()
@MongoTransactional()
async update(id: string, updateRecipeDto: UpdateRecipeDto): Promise<Recipe> {
const ret = await this.recipeRepository.update(id, updateRecipeDto);
if (!ret) throw new NotFoundException('Recipe not found');
Expand Down
7 changes: 0 additions & 7 deletions api/libs/user/src/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<User> {
const { email, username } = createUserDto;
const [dupEmail, dupUsername] = await Promise.all([
Expand All @@ -29,13 +27,11 @@ export class UserService {
}

@Logable()
@MongoTransactional({ readOnly: true })
async findAll(filterDto: any): Promise<User[]> {
return await this.userRepository.findAll(filterDto);
}

@Logable()
@MongoTransactional({ readOnly: true })
async findOne(id: string): Promise<User> {
const ret = await this.userRepository.findOne(id);
if (!ret) {
Expand All @@ -45,13 +41,11 @@ export class UserService {
}

@Logable()
@MongoTransactional({ readOnly: true })
async findByEmail(email: string): Promise<User> {
return await this.userRepository.findByEmail(email);
}

@Logable()
@MongoTransactional()
async update(id: string, updateDto: UpdateUserDto): Promise<User> {
const { username } = updateDto;
const dupUsername = await this.userRepository.findByUsername(username);
Expand All @@ -66,7 +60,6 @@ export class UserService {
}

@Logable()
@MongoTransactional()
async deleteOne(id: string): Promise<User> {
const ret = await this.userRepository.deleteOne(id);
if (!ret) {
Expand Down

0 comments on commit fa871a5

Please sign in to comment.