-
Notifications
You must be signed in to change notification settings - Fork 2
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
장소 저장할 때 ES에도 저장 #164
장소 저장할 때 ES에도 저장 #164
Changes from all commits
b938e05
108a13a
5f56fe0
0d91f7d
68f9947
35079ed
255aacc
6d17f6a
c3c3c10
cee82da
2bd74aa
adb4d87
833cfec
16dacf6
5613a4a
aee978c
33a1c63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { BatchService } from '@src/batch/batch.service'; | ||
import { PinoLogger } from 'nestjs-pino'; | ||
import { PlaceRepository } from '@src/place/place.repository'; | ||
import { SearchModule } from '@src/search/search.module'; | ||
|
||
@Module({ | ||
imports: [SearchModule], | ||
providers: [BatchService, PlaceRepository, PinoLogger], | ||
}) | ||
export class BatchModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Injectable } from '@nestjs/common'; | ||
import { PinoLogger } from 'nestjs-pino'; | ||
import { Cron, CronExpression } from '@nestjs/schedule'; | ||
import { PlaceRepository } from '@src/place/place.repository'; | ||
import { SearchService } from '@src/search/search.service'; | ||
|
||
@Injectable() | ||
export class BatchService { | ||
constructor( | ||
private readonly searchService: SearchService, | ||
private readonly placeRepository: PlaceRepository, | ||
private readonly logger: PinoLogger, | ||
) {} | ||
|
||
@Cron(CronExpression.EVERY_HOUR) | ||
async syncPlacesToElastic() { | ||
this.logger.debug(`syncPlacesToElastic() 배치 시작`); | ||
try { | ||
this.logger.debug(`동기화 작업을 시작합니다.`); | ||
const places = await this.placeRepository.findUpdatedPlacesForTwoHours(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. q. 수동으로 동기화 한 것 포함해서 모두 동기화하나요? 많지 않아서 괜찮을 것 같습니다~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만약 수동으로 잘 저장되는 데이터 수가 아주 많아서, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
넵! 현재는 그런 상황이고 만약
맞습니다! 같이 고민해봐야 될 부분인 것 같네요 |
||
this.logger.debug(`동기화 할 장소의 갯수: ${places.length}`); | ||
|
||
await this.searchService.syncPlaceToElasticSearch(places); | ||
this.logger.debug(`동기화 작업이 완료되었습니다.`); | ||
} catch (error) { | ||
this.logger.error(`동기화 작업 중 에러가 발생했습니다: ${error}`); | ||
} finally { | ||
this.logger.debug(`syncPlacesToElastic() 배치 종료`); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,26 @@ | ||
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; | ||
import { CourseService } from '../course.service'; | ||
import { CoursePermissionException } from '../exception/CoursePermissionException'; | ||
import { AdminGuard } from '@src/admin/guard/AdminGuard'; | ||
|
||
@Injectable() | ||
export class CoursePermissionGuard implements CanActivate { | ||
constructor(private readonly courseService: CourseService) {} | ||
constructor( | ||
private readonly adminGuard: AdminGuard, | ||
private readonly courseService: CourseService, | ||
) {} | ||
|
||
async canActivate(context: ExecutionContext): Promise<boolean> { | ||
const isAdmin = this.adminGuard.isAdmin(context); | ||
if (isAdmin) { | ||
return true; | ||
} | ||
|
||
const request = context.switchToHttp().getRequest(); | ||
const courseId = Number(request.params.id); | ||
const userId = Number(request.user.userId); | ||
|
||
const course = await this.courseService.getCourseOwnerId(courseId); | ||
if (course !== userId) { | ||
const courseOwnerId = await this.courseService.getCourseOwnerId(courseId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. p2. 항상 함께 사용될 것 같은데 인증 가드를 상속해 사용하면 어떨까요? 참고 : AdminGuard There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. q. 밑에서 다시 사용하나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
가독성 고려했습니다! |
||
if (courseOwnerId !== userId) { | ||
throw new CoursePermissionException(courseId); | ||
} | ||
return true; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,16 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { forwardRef, Module } from '@nestjs/common'; | ||
import { PlaceController } from './place.controller'; | ||
import { PlaceService } from './place.service'; | ||
import { PlaceRepository } from './place.repository'; | ||
import { ConfigModule } from '@nestjs/config'; | ||
import { SearchModule } from '@src/search/search.module'; | ||
import { SearchService } from '@src/search/search.service'; | ||
import { PinoLogger } from 'nestjs-pino'; | ||
|
||
@Module({ | ||
imports: [ConfigModule], | ||
imports: [ConfigModule, forwardRef(() => SearchModule)], | ||
controllers: [PlaceController], | ||
providers: [PlaceService, PlaceRepository], | ||
providers: [PlaceService, PlaceRepository, SearchService, PinoLogger], | ||
exports: [PlaceRepository], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. q. 이거 테스트 때문에 로거 추가하신건가요? 저도 비슷하게 글로벌 모듈로 이미 등록된 ConfigModule 을 다시 import 했는데요, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
테스트 때문에 추가했습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 기존의 nest 에서 제공하는 |
||
}) | ||
export class PlaceModule {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { Place } from '@src/place/entity/place.entity'; | ||
|
||
export class ESPlaceSaveDTO { | ||
constructor( | ||
readonly id: number, | ||
readonly googlePlaceId: string, | ||
readonly name: string, | ||
readonly thumbnailUrl: string, | ||
readonly rating: number, | ||
readonly location: { | ||
latitude: number; | ||
longitude: number; | ||
}, | ||
readonly formattedAddress: string, | ||
readonly category: string, | ||
readonly description: string, | ||
readonly detailPageUrl: string, | ||
readonly createdAt: Date, | ||
readonly updatedAt: Date, | ||
readonly deletedAt: Date, | ||
) {} | ||
|
||
static from(place: Place) { | ||
return new ESPlaceSaveDTO( | ||
place.id, | ||
place.googlePlaceId, | ||
place.name, | ||
place.thumbnailUrl, | ||
place.rating, | ||
{ | ||
latitude: place.latitude, | ||
longitude: place.longitude, | ||
}, | ||
place.formattedAddress, | ||
place.category, | ||
place.description, | ||
place.detailPageUrl, | ||
place.createdAt, | ||
place.updatedAt, | ||
place.deletedAt, | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { BaseException } from '@src/common/exception/BaseException'; | ||
import { HttpStatus } from '@nestjs/common'; | ||
|
||
export class ElasticSearchException extends BaseException { | ||
constructor(id?: number) { | ||
const message = id | ||
? `id:${id} ElasticSearch에 데이터를 저장하는데 실패했습니다.` | ||
: 'ElasticSearch에 데이터를 저장하는데 실패했습니다.'; | ||
super({ | ||
code: 1003, | ||
message, | ||
status: HttpStatus.INTERNAL_SERVER_ERROR, | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q. 테스트에서 datasource 를 오버라이드해서 사용하는데,
이 설정도 따로 적용해야 할까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수정했습니다!