-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* [chore]: bull.js 사용을 위한 환경 설정 (#103) * POG-143 [chore]: bull 의존성 설치 1. @nestjs/bull, bull, @types/bull 설치 * POG-143 [chore]: bull 의존성 설정 1. BullModule 설정 * POG-143 [chore]: Push 모노레포 설정 준비 * POG-143 [chore]: BullModule 설정 * POG-143 [chore]: BullQueue 환경 설정 1. BullQueue를 활용할 수 있도록 환경 설정 * POG-143 [chore]: nest-cli 모노레포 환경 추가 1. 서버를 실행할 때, 앱서버와 푸시서버를 나눠서 관리할 때, sourceRoot를 재설정할 필요가 있음 * [chore]: bull-monitor를 활용한 Queue 모니터링 구축 (#105) 1. @bull-monitor/express 의존성 설치를 통한 Queue 모니터링 구축 준비 2. BullMonitorModule, BullMonitorService 설정을 통한 Queue 모니터링 구축 * [chore]: CacheModule, in-memory 구성을 위한 의존성 설치 (#107) - redis 적용을 위해 CacheModule 구성했음. - CacheModule 적용을 위해 cache-manager, @types/cache-manager 설치 - CacheModule에 Redis 적용을 위해 cache-manager-ioredis, @types/cache-manager-ioredis 설치 * [feat]: 즐겨찾기 추가 API 호출 시, Redis 캐시 적용 (#110) 1. 만약 특정 소환사를 즐겨찾기 했을 때, 캐시에 데이터가 없으면, 전적 확인을 위한 Redis 캐시 추가 2. 임시적으로 캐시 만료 시간 제거, 캐싱 전략에 따라 만료 시간을 수정할 예정. 3. Redis 캐시에 저장하는 데이터는 삭제되어도 무관한 정보들임. 4. 만약 Redis 서버가 장애가 났을 때, 데이터가 삭제된다면, DB에 있는 데이터를 Redis에 저장하는 Cache Warming 작업을 진행해야 함. 5. 만약, DB에 있는 소환사 전적 데이터가 최신 정보가 아닐 시에는, Riot API를 호출해서, 최신 데이터를 Redis에 저장해야 함. #111 * [feat]: 즐겨찾기 삭제 API 호출 시, Redis 캐시 적용 (#112) 1. 아무도 즐겨찾기 하지 않는 소환사의 경우 Redis 캐시에서도 데이터가 삭제되게끔 설정 2. 테스트 코드 수정 * [fix]: 캐시를 Redis Client를 활용하는 방법으로 환경 변경 (#117) ## 작업사항 - 기존, NestJS에서 제공하는 cacheModule과 Redis를 함께 활용하는 방법을 구성했으나, 이렇게 활용하면 Redis의 많은 자료구조를 활용할 수 없는 문제가 있었음. - Redis를 폭넓게 활용하기 위해서 Redis Client를 통해 Redis를 활용하는 방법을 구성함. - nestjs-redis를 활용할 때, 순환 참조 문제가 발생함에 따라, 의존성 설정 변경 (skunight/nestjs-redis#82) - 환경 변경을 통해, 즐겨찾기 추가, 삭제 API를 호출할 때, Redis 캐시가 적용되도록 변경 - cacheManager를 주입 받게 되어있던 테스트 환경도 수정 ## 관계된 이슈, PR #104 #111 #113 ## 참고 https://www.npmjs.com/package/nestjs-redis https://ably.com/blog/migrating-from-node-redis-to-ioredis skunight/nestjs-redis#82 * [feat]: 즐겨찾기 추가, 취소 API 호출 시, Redis에 summonerId 관리 로직 구성 (#120) 1. 즐겨찾기 추가 API 호출 시, Redis Set 자료구조 방식으로, summonerId를 키로 하고, 값으로 입력받은 summonerId를 구성 2. 즐겨찾기 취소 API 호출 시, 아무도 즐겨찾기 하지 않는 사용자는 summonerId를 Set 키에서 제거하는 로직 구성 3. sadd, srem stub 로직 추가 * [feat]: Riot API와 비교해서, 전적이 변동됐을 때 로직 구성 (#121) 1. pushQueue에 EnQueue 작업 추가 2. 현재 Redis의 기록과 Riot API의 기록을 비교하는 로직 추가 3. 기록이 변경됐으면, Riot API에서 얻은 데이터를 Redis 기록에 수정하는 로직 추가 4. Queue 내용 추가 5. 불필요한 로직 제거 * [feat]: 일정 시간마다 푸시 보내기 위한 Task Schedule 설정 (#123) 1. Task Schedule을 위한 의존성 설치 2. 5분마다 푸시를 보낼 수 있도록 로직 구성 * [feat]: Topic을 활용한 FCM push 로직 구성 (#124) 1. FCM push 활용을 위한 firebase-admin 설정 2. json도 불러올 수 있게끔 tsconfig.json 변경 3. pushJob을 모듈 단위로 설정할 수 있게끔 설정 4. 푸시 테스트를 위해 필요 로직 주석 처리 * [chore]: TypeORM Quert Timeout 설정 (#126) 1. 슬로우 쿼리가 발생했을 때, 성능저하를 막기 위해 쿼리 시간이 특정 시간 이상 지속되는 경우 timeout으로 종료시키는 설정 추가 2. timeout 설정을 통해 장애 전파 최소화 * [fix]: 즐겨찾기 조회 API 쿼리 튜닝 및 인덱스 재설정 (#128) ## 작업사항 - 즐겨찾기 조회 API의 기존 쿼리는 1000만건 데이터를 조회할 때 응답속도가 약 1.5초가 걸리는 상황이었음. - 데이터가 많아질수록 비효율적인 쿼리 방식이었음. - FavoriteSummoner 테이블에 user_id 인덱스를 추가하여, Seq Scan이 아닌 Index Scan을 활용하도록 설정 - 쿼리 튜닝으로 인하여 1000만건 데이터를 조회할 때 1.5초에서 0.01초로 줄일 수 있었음. - 유니크 제약이 걸려있는 컬럼에 인덱스를 설정해서, 중복으로 인덱스가 설정되어있었던 상황이었고, 인덱스 중복을 제거함. ## 관계된 이슈, PR #75 * [fix]: favorite_summoner 테이블 인덱스 변경 (#129) ## 작업사항 1. 복합 인덱스 설정을 통한 쿼리 성능 향상 ## 관계된 이슈, PR #75 ## 작업 내용 https://overcome-the-limits.tistory.com/666 * [feat]: Redis 장애 복구 API 추가 (#131) ## 작업사항 1. Redis 서버 장애 시, 데이터가 모두 사라질 경우를 대비해서, RDS를 활용하여 Redis에 데이터를 추가하는 작업 로직 추가 ## 관계된 이슈, PR #115 * [chore]: 환경 변수 분리 (#132) ## 작업사항 1. 배포 전, development, production 별로 다르게 동작하도록 설정 ## 관계된 이슈, PR #31
- Loading branch information
Showing
42 changed files
with
4,521 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
*.env | ||
env_files/* | ||
db_data | ||
pog-adminsdk.json | ||
|
||
# compiled output | ||
/dist | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { PushApiModule } from './push/PushApiModule'; | ||
import { getBullModule } from '../../../libs/entity/getBullModule'; | ||
import { HealthCheckController } from './health-check/HealthCheckController'; | ||
import { getTypeOrmModule } from '../../../libs/entity/getTypeOrmModule'; | ||
import { LoggingModule } from '@app/common-config/logging/logging.module'; | ||
import { Module } from '@nestjs/common'; | ||
import { ConfigModule } from '@nestjs/config'; | ||
import { TerminusModule } from '@nestjs/terminus'; | ||
import { HttpModule } from '@nestjs/axios'; | ||
|
||
import { AuthConfig, ValidationSchema } from '@app/common-config/config'; | ||
import { BullMonitorModule } from '../../../libs/entity/queue/src/bull-monitor/BullMonitorModule'; | ||
|
||
@Module({ | ||
imports: [ | ||
ConfigModule.forRoot({ | ||
load: [AuthConfig], | ||
isGlobal: true, | ||
validationSchema: ValidationSchema, | ||
}), | ||
getTypeOrmModule(), | ||
getBullModule(), | ||
BullMonitorModule, | ||
LoggingModule, | ||
TerminusModule, | ||
HttpModule, | ||
PushApiModule, | ||
], | ||
controllers: [HealthCheckController], | ||
}) | ||
export class PushAppModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Controller, Get } from '@nestjs/common'; | ||
import { | ||
HealthCheckService, | ||
HttpHealthIndicator, | ||
TypeOrmHealthIndicator, | ||
HealthCheck, | ||
} from '@nestjs/terminus'; | ||
|
||
@Controller('health-check') | ||
export class HealthCheckController { | ||
constructor( | ||
private health: HealthCheckService, | ||
// private http: HttpHealthIndicator, | ||
private db: TypeOrmHealthIndicator, | ||
) {} | ||
|
||
@Get() | ||
@HealthCheck() | ||
check() { | ||
return this.health.check([ | ||
// () => this.http.pingCheck('nestjs-docs', 'https://docs.nestjs.com'), | ||
() => this.db.pingCheck('database'), | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { NestFactory } from '@nestjs/core'; | ||
import * as winston from 'winston'; | ||
import { | ||
utilities as nestWinstonModuleUtilities, | ||
WinstonModule, | ||
} from 'nest-winston'; | ||
import { PushAppModule } from './PushAppModule'; | ||
import { NestExpressApplication } from '@nestjs/platform-express'; | ||
import { Logger } from '@nestjs/common'; | ||
import { SetNestApp } from '@app/common-config/setNestApp'; | ||
|
||
class Application { | ||
private logger = new Logger(Application.name); | ||
private PORT: string; | ||
private DEV_MODE: boolean; | ||
|
||
constructor(private server: NestExpressApplication) { | ||
this.server = server; | ||
this.PORT = process.env.PUSH_PORT; | ||
this.DEV_MODE = process.env.NODE_ENV === 'production' ? false : true; | ||
} | ||
|
||
async bootstrap() { | ||
SetNestApp(this.server); | ||
await this.server.listen(this.PORT); | ||
} | ||
|
||
startLog() { | ||
if (this.DEV_MODE) { | ||
this.logger.log(`✅ Server on http://localhost:${this.PORT}`); | ||
} else { | ||
this.logger.log(`✅ Server on port ${this.PORT}...`); | ||
} | ||
} | ||
} | ||
|
||
async function bootstrap(): Promise<void> { | ||
const server = await NestFactory.create<NestExpressApplication>( | ||
PushAppModule, | ||
{ | ||
logger: WinstonModule.createLogger({ | ||
transports: [ | ||
new winston.transports.Console({ | ||
level: process.env.NODE_ENV === 'production' ? 'info' : 'silly', | ||
format: winston.format.combine( | ||
winston.format.timestamp(), | ||
nestWinstonModuleUtilities.format.nestLike('PushApp', { | ||
prettyPrint: true, | ||
}), | ||
), | ||
}), | ||
], | ||
}), | ||
}, | ||
); | ||
|
||
const app = new Application(server); | ||
await app.bootstrap(); | ||
app.startLog(); | ||
} | ||
|
||
bootstrap().catch(error => { | ||
new Logger('init').error(error); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { PushApiService } from './PushApiService'; | ||
import { PushJobService } from './../../../../libs/common-config/src/job/src/PushJobService'; | ||
import { Process, Processor } from '@nestjs/bull'; | ||
import { Logger } from '@nestjs/common'; | ||
import { Job } from 'bull'; | ||
import { plainToInstance } from 'class-transformer'; | ||
import { RiotApiJobs } from '@app/common-config/job/RiotApi'; | ||
import { PushRiotApi } from './dto/PushRiotApi'; | ||
|
||
@Processor('PushQueue') | ||
export class PushApiConsumer { | ||
private readonly logger = new Logger(PushApiConsumer.name); | ||
|
||
constructor( | ||
private readonly pushJobService: PushJobService, | ||
private readonly pushApiService: PushApiService, | ||
) {} | ||
|
||
@Process('summonerList') | ||
async getSummonerIdQueue(job: Job) { | ||
await this.pushJobService.send(job.data['summonerId']); | ||
this.logger.log(`${job.data['summonerId']} topic 푸시를 전송했습니다.`); | ||
} | ||
|
||
@Process('recoverList') | ||
async getRecoverQueue(job: Job) { | ||
const redisClient = await this.pushApiService.getRedisClient(); | ||
const riotApiResponse = plainToInstance( | ||
PushRiotApi, | ||
await RiotApiJobs(job.data['summonerId']), | ||
); | ||
await this.pushApiService.changeRecord( | ||
riotApiResponse, | ||
redisClient, | ||
job.data['summonerId'], | ||
); | ||
|
||
await this.pushApiService.addRedisSet(redisClient, job.data['summonerId']); | ||
this.logger.log(`${job.data}를 Redis에 추가했습니다.`); | ||
} | ||
} |
Oops, something went wrong.