-
Notifications
You must be signed in to change notification settings - Fork 1
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
[Feat/#215] article_view_his 테이블 추가 및 조회수 응답 추가 #216
Changes from 12 commits
3c02659
977de9a
1334ccf
390b898
2304654
29ca0fb
bfaebe6
362999e
9c17140
abde0c3
89a188f
a8342ba
21c0ad4
4ce6ac9
51671e4
a76ed19
dc76e36
7bac2fc
ba64abd
3348881
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.few.api.repo.dao.article | ||
|
||
import com.few.api.repo.dao.article.command.ArticleViewHisCommand | ||
import com.few.api.repo.dao.article.query.ArticleViewHisCountQuery | ||
import jooq.jooq_dsl.tables.ArticleViewHis | ||
import org.jooq.DSLContext | ||
import org.springframework.stereotype.Repository | ||
|
||
@Repository | ||
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. 종준님은 DAO에 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. |
||
class ArticleViewHisDao( | ||
private val dslContext: DSLContext, | ||
) { | ||
|
||
fun insertArticleViewHis(command: ArticleViewHisCommand) { | ||
dslContext.insertInto( | ||
ArticleViewHis.ARTICLE_VIEW_HIS, | ||
ArticleViewHis.ARTICLE_VIEW_HIS.ARTICLE_MST_ID, | ||
ArticleViewHis.ARTICLE_VIEW_HIS.MEMBER_ID | ||
).values( | ||
command.articleId, | ||
command.memberId | ||
).execute() | ||
} | ||
Comment on lines
+14
to
+23
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.
|
||
|
||
fun countArticleViews(query: ArticleViewHisCountQuery): Long? { | ||
return dslContext.selectCount() | ||
.from(ArticleViewHis.ARTICLE_VIEW_HIS) | ||
.where(ArticleViewHis.ARTICLE_VIEW_HIS.ARTICLE_MST_ID.eq(query.articleId)) | ||
.fetchOne(0, Long::class.java) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.few.api.repo.dao.article.command | ||
|
||
data class ArticleViewHisCommand( | ||
val articleId: Long, | ||
val memberId: Long, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.few.api.repo.dao.article.query | ||
|
||
data class ArticleViewHisCountQuery( | ||
val articleId: Long, | ||
) |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.few.api.config | ||
|
||
import com.few.api.config.properties.ThreadPoolProperties | ||
import io.github.oshai.kotlinlogging.KotlinLogging | ||
import org.springframework.boot.context.properties.ConfigurationProperties | ||
import org.springframework.context.annotation.Bean | ||
import org.springframework.context.annotation.Configuration | ||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor | ||
|
||
@Configuration | ||
class DatabaseAccessThreadPoolConfig { | ||
private val log = KotlinLogging.logger {} | ||
|
||
companion object { | ||
const val DATABASE_ACCESS_POOL = "database-task-" | ||
} | ||
|
||
@Bean | ||
@ConfigurationProperties(prefix = "database.thread-pool") | ||
fun databaseAccessThreadPoolProperties(): ThreadPoolProperties { | ||
return ThreadPoolProperties() | ||
} | ||
|
||
@Bean(DATABASE_ACCESS_POOL) | ||
fun databaseAccessThreadPool() = ThreadPoolTaskExecutor().apply { | ||
val properties = databaseAccessThreadPoolProperties() | ||
corePoolSize = properties.getCorePoolSize() | ||
maxPoolSize = properties.getMaxPoolSize() | ||
queueCapacity = properties.getQueueCapacity() | ||
setWaitForTasksToCompleteOnShutdown(properties.getWaitForTasksToCompleteOnShutdown()) | ||
setAwaitTerminationSeconds(properties.getAwaitTerminationSeconds()) | ||
setThreadNamePrefix("databaseAccessThreadPool-") | ||
setRejectedExecutionHandler { r, _ -> | ||
log.warn { "Database Access Task Rejected: $r" } | ||
} | ||
initialize() | ||
} | ||
Comment on lines
+10
to
+37
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. 디코 훅 쓰레드 풀이랑 똑같이 디비 접근용 쓰레드 풀 생성. 추후 이걸 활용할 것들이 많아보여서 네이밍을 좀 일반적이게 했어요(조회수랑 관련없이) |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
package com.few.api.domain.article.usecase | ||
|
||
import com.few.api.config.DatabaseAccessThreadPoolConfig.Companion.DATABASE_ACCESS_POOL | ||
import com.few.api.domain.article.usecase.dto.ReadArticleUseCaseIn | ||
import com.few.api.domain.article.usecase.dto.ReadArticleUseCaseOut | ||
import com.few.api.domain.article.usecase.dto.WriterDetail | ||
|
@@ -9,8 +10,13 @@ import com.few.api.domain.article.service.dto.BrowseArticleProblemIdsInDto | |
import com.few.api.domain.article.service.dto.ReadWriterRecordInDto | ||
import com.few.api.exception.common.NotFoundException | ||
import com.few.api.repo.dao.article.ArticleDao | ||
import com.few.api.repo.dao.article.ArticleViewHisDao | ||
import com.few.api.repo.dao.article.command.ArticleViewHisCommand | ||
import com.few.api.repo.dao.article.query.ArticleViewHisCountQuery | ||
import com.few.api.repo.dao.article.query.SelectArticleRecordQuery | ||
import com.few.data.common.code.CategoryType | ||
import io.github.oshai.kotlinlogging.KotlinLogging | ||
import org.springframework.scheduling.annotation.Async | ||
import org.springframework.stereotype.Component | ||
import org.springframework.transaction.annotation.Transactional | ||
|
||
|
@@ -19,8 +25,11 @@ class ReadArticleUseCase( | |
private val articleDao: ArticleDao, | ||
private val readArticleWriterRecordService: ReadArticleWriterRecordService, | ||
private val browseArticleProblemsService: BrowseArticleProblemsService, | ||
private val articleViewHisDao: ArticleViewHisDao, | ||
) { | ||
|
||
private val log = KotlinLogging.logger {} | ||
|
||
@Transactional(readOnly = true) | ||
fun execute(useCaseIn: ReadArticleUseCaseIn): ReadArticleUseCaseOut { | ||
val articleRecord = SelectArticleRecordQuery(useCaseIn.articleId).let { query: SelectArticleRecordQuery -> | ||
|
@@ -31,9 +40,14 @@ class ReadArticleUseCase( | |
readArticleWriterRecordService.execute(query) ?: throw NotFoundException("writer.notfound.id") | ||
} | ||
|
||
val problemIds = BrowseArticleProblemIdsInDto(articleRecord.articleId).let { query: BrowseArticleProblemIdsInDto -> | ||
browseArticleProblemsService.execute(query) | ||
} | ||
val problemIds = | ||
BrowseArticleProblemIdsInDto(articleRecord.articleId).let { query: BrowseArticleProblemIdsInDto -> | ||
browseArticleProblemsService.execute(query) | ||
} | ||
|
||
val views = (articleViewHisDao.countArticleViews(ArticleViewHisCountQuery(useCaseIn.articleId)) ?: 0L) + 1L | ||
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. 조회수 가져온 뒤에 우선 + 1 하도록 변경 |
||
|
||
insertArticleViewHisAsync(useCaseIn.articleId, useCaseIn.memberId) | ||
|
||
return ReadArticleUseCaseOut( | ||
id = articleRecord.articleId, | ||
|
@@ -46,7 +60,19 @@ class ReadArticleUseCase( | |
content = articleRecord.content, | ||
problemIds = problemIds.problemIds, | ||
category = CategoryType.convertToDisplayName(articleRecord.category), | ||
createdAt = articleRecord.createdAt | ||
createdAt = articleRecord.createdAt, | ||
views = views | ||
) | ||
} | ||
|
||
@Async(value = DATABASE_ACCESS_POOL) | ||
@Transactional | ||
fun insertArticleViewHisAsync(articleId: Long, memberId: Long) { | ||
try { | ||
articleViewHisDao.insertArticleViewHis(ArticleViewHisCommand(articleId, memberId)) | ||
log.debug { "Successfully inserted article view history for articleId: $articleId and memberId: $memberId" } | ||
} catch (e: Exception) { | ||
log.error { "Failed to insert article view history for articleId: $articleId and memberId: $memberId" } | ||
} | ||
} | ||
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. Insert 는 DATABASE_ACCESS_POOL 풀에서 수행하도록 변경. 어차피 다른 쓰레드에서 수행되기 때문에 기존 아티클을 조회하던 쓰레드와 트랜잭션 컨텍스트를 공유하지 않고, 따라서 트랜잭션 전파 레벨 지정은 필요 없음. (전파 자체가 안됨, new transaction) 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. 해당 로직은 일단 UC 내부에 넣어뒀는데 서비스로 뺴기도 애매한게, 같은 도메인이여서,, 좋은 생각있음 공유좀요 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. 일단 handler로 함... 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.
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,11 @@ discord: | |
queue-capacity: ${DISCORD_THREAD_POOL_QUEUE_CAPACITY:30} | ||
wait-for-tasks-to-complete-on-shutdown: ${DISCORD_THREAD_POOL_WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN:true} | ||
await-termination-seconds: ${DISCORD_THREAD_POOL_AWAIT_TERMINATION_SECONDS:60} | ||
|
||
database: | ||
thread-pool: | ||
core-pool-size: 10 | ||
max-pool-size: 30 | ||
queue-capacity: 70 | ||
wait-for-tasks-to-complete-on-shutdown: true | ||
await-termination-seconds: 60 | ||
Comment on lines
+17
to
+23
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. 이건 VM 환경변수로 뺼까요? 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. 이거 설정하면서 든 생각이, 만약 조회가 엄청 많이 발생하는 상황에선 max 개수인 30 + queue 대기 70 해서 100 명 까지만 Insert가 될 거 같음... 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. 그럼 databaseAccessThreadPool의 setRejectedExecutionHandler 부분을 수정하면 되지 않을까요? |
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
-- 아티클 조회수 저장 테이블 | ||
CREATE TABLE ARTICLE_VIEW_HIS | ||
( | ||
id BIGINT NOT NULL AUTO_INCREMENT, | ||
article_mst_id BIGINT NOT NULL, | ||
member_id BIGINT NOT NULL, | ||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
deleted_at TIMESTAMP NULL DEFAULT NULL, | ||
PRIMARY KEY (id) | ||
); | ||
Comment on lines
+2
to
+10
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.
|
||
|
||
-- [인덱스 추가] -- | ||
CREATE INDEX article_view_his_idx1 ON ARTICLE_VIEW_HIS (article_mst_id); |
This file was deleted.
This file was deleted.
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.
각 모듈별로 jooq 필드시 생성되는 .sql 파일이 gitignore되어있었는데, 최상위 위치에 통합관리하도록 변경했습니다