Skip to content
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: QuestionSheet Scheduler #38

Merged
merged 6 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions api/src/main/kotlin/com/mashup/dojo/config/SchedulerConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,15 @@ class SchedulerConfig {
setWaitForTasksToCompleteOnShutdown(true)
}
}

@Bean(name = ["questionSheetSchedulerExecutor"])
fun questionSheetSchedulerExecutor(): Executor {
return ThreadPoolTaskExecutor().apply {
corePoolSize = 5
maxPoolSize = 5
queueCapacity = 20
setThreadNamePrefix("questionSheetScheduler-")
setWaitForTasksToCompleteOnShutdown(true)
}
}
}
10 changes: 7 additions & 3 deletions api/src/main/kotlin/com/mashup/dojo/scheduler/Scheduler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,19 @@ private val log = KotlinLogging.logger {}
class Scheduler(
private val questionUseCase: QuestionUseCase,
) {
@Scheduled(cron = SCHEDULED_CRON)
@Scheduled(cron = "\${scheduler.cron}")
@Async("questionSetSchedulerExecutor")
fun createQuestionSet() {
log.info { "=== Start Create questionSet at ${LocalDateTime.now()}. ===" }
questionUseCase.createQuestionSet()
log.info { "=== Done Create questionSet at ${LocalDateTime.now()}. ===" }
}

companion object {
private const val SCHEDULED_CRON = "0 0 9,21 * * *"
@Scheduled(cron = "\${scheduler.sheet-cron}")
@Async("questionSheetSchedulerExecutor")
fun createQuestionSheet() {
log.info { "=== Start Create questionSheet at ${LocalDateTime.now()}. ===" }
questionUseCase.createQuestionSheet()
log.info { "=== Done Create questionSheet at ${LocalDateTime.now()}. ===" }
}
}
4 changes: 4 additions & 0 deletions api/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ spring:
name: api
profiles:
include: entity, common

scheduler:
cron: "0 0 9,21 * * *"
sheet-cron: "0 5 9,21 * * *"
2 changes: 2 additions & 0 deletions common/src/main/kotlin/com/mashup/dojo/DojoExceptionType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ enum class DojoExceptionType(
ACCESS_DENIED("Access denied. Check authentication.", "C007_ACCESS_DENIED", 403),
AUTHENTICATION_FAILURE("Authentication failed. Check login.", "C008_AUTHENTICATION_FAILURE", 401),
ARGUMENT_NOT_VALID("Method Argument Not Valid. Check argument validation.", "C009_ARGUMENT_NOT_VALID", 400),
INVALID_MEMBER_GENDER("The gender does not exist.", "C011_INVALID_MEMBER_GENDER", 400),
INVALID_MEMBER_PLATFORM("The platform does not exist.", "C010_INVALID_MEMBER_PLATFORM", 400),
}
44 changes: 44 additions & 0 deletions service/src/main/kotlin/com/mashup/dojo/domain/Member.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mashup.dojo.domain

import com.mashup.dojo.DojoException
import com.mashup.dojo.DojoExceptionType
import com.mashup.dojo.UUIDGenerator
import java.time.LocalDateTime

Expand Down Expand Up @@ -66,12 +68,46 @@ data class Member(
updatedAt = LocalDateTime.now()
)
}

internal fun convertToMember(
id: String,
fullName: String,
secondInitialName: String,
profileImageId: ImageId?,
ordinal: Int,
platform: MemberPlatform,
gender: MemberGender,
point: Int,
createdAt: LocalDateTime,
updatedAt: LocalDateTime,
): Member {
return Member(
id = MemberId(id),
fullName = fullName,
secondInitialName = secondInitialName,
profileImageId = profileImageId,
ordinal = ordinal,
platform = platform,
gender = gender,
point = point,
createdAt = createdAt,
updatedAt = updatedAt
)
}
}
}

enum class MemberGender {
MALE,
FEMALE,
;

companion object {
fun findByValue(value: String): MemberGender {
return entries.find { it.name.equals(value, ignoreCase = true) }
xonmin marked this conversation as resolved.
Show resolved Hide resolved
?: throw DojoException.of(DojoExceptionType.INVALID_MEMBER_GENDER)
}
}
}

enum class MemberPlatform {
Expand All @@ -81,4 +117,12 @@ enum class MemberPlatform {
ANDROID,
IOS,
DESIGN,
;

companion object {
fun findByValue(value: String): MemberPlatform {
return entries.find { it.name.equals(value, ignoreCase = true) }
?: throw DojoException.of(DojoExceptionType.INVALID_MEMBER_PLATFORM)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ interface MemberService {

fun create(command: CreateMember): MemberId

fun findAllMember(): List<Member>

data class CreateMember(
val fullName: String,
val profileImageId: ImageId?,
Expand Down Expand Up @@ -90,6 +92,28 @@ class DefaultMemberService(
return MemberId(id)
}

override fun findAllMember(): List<Member> {
return memberRepository.findAll()
.map { m ->
val platform = MemberPlatform.findByValue(m.platform)
val gender = MemberGender.findByValue(m.gender)
val imageId = m.profileImageId?.let { ImageId(it) }

Member.convertToMember(
id = m.id,
fullName = m.fullName,
secondInitialName = m.secondInitialName,
profileImageId = imageId,
ordinal = m.ordinal,
platform = platform,
gender = gender,
point = m.point,
createdAt = m.createdAt,
updatedAt = m.updatedAt
)
}
}

private fun mockMember(memberId: MemberId) =
Member(
memberId, "์ž„์ค€ํ˜•", "ใ…ˆ", ImageId("123456"), MemberPlatform.SPRING, 14, MemberGender.MALE, 200, LocalDateTime.now(), LocalDateTime.now()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.mashup.dojo.service

import com.mashup.dojo.domain.Candidate
import com.mashup.dojo.domain.ImageId
import com.mashup.dojo.domain.Member
import com.mashup.dojo.domain.MemberId
import com.mashup.dojo.domain.Question
import com.mashup.dojo.domain.QuestionCategory
import com.mashup.dojo.domain.QuestionId
import com.mashup.dojo.domain.QuestionOrder
import com.mashup.dojo.domain.QuestionSet
import com.mashup.dojo.domain.QuestionSetId
import com.mashup.dojo.domain.QuestionSheet
import com.mashup.dojo.domain.QuestionSheetId
import com.mashup.dojo.domain.QuestionType
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Service
Expand All @@ -31,6 +36,11 @@ interface QuestionService {
publishedAt: LocalDateTime,
): QuestionSet

fun createQuestionSheets(
questionSet: QuestionSet?,
members: List<Member>,
): List<QuestionSheet>

fun getQuestionById(id: QuestionId): Question?
}

Expand Down Expand Up @@ -81,6 +91,23 @@ class DefaultQuestionService : QuestionService {
return SAMPLE_QUESTION_SET
}

override fun createQuestionSheets(
questionSet: QuestionSet?,
members: List<Member>,
): List<QuestionSheet> {
/**
* TODO:
* target : members
* question : QuestionSet
* candidate : member.candidate()
*
* - make friend logic, get Candidate logic
* - cache put -> QuestionSet and return
* - Temporarily set to create for all members, discuss details later
*/
return LIST_SAMPLE_QUESTION_SHEET
}

override fun getQuestionById(id: QuestionId): Question? {
// TODO("Not yet implemented")
return SAMPLE_QUESTION
Expand Down Expand Up @@ -119,5 +146,24 @@ class DefaultQuestionService : QuestionService {
),
publishedAt = LocalDateTime.now()
)

private val SAMPLE_QUESTION_SHEET =
QuestionSheet(
questionSheetId = QuestionSheetId("1"),
questionSetId = SAMPLE_QUESTION_SET.id,
questionId = QuestionId("1"),
resolverId = MemberId("1"),
candidates =
listOf(
Candidate(MemberId("2"), "์ž„์ค€ํ˜•", 1),
Candidate(MemberId("3"), "ํ•œ์”จ", 1),
Candidate(MemberId("4"), "๋ฐ•์”จ", 1),
Candidate(MemberId("5"), "์˜ค์”จ", 1)
)
)

// TODO: Set to 3 sheets initially. Need to modify for all users later.
val LIST_SAMPLE_QUESTION_SHEET =
listOf(SAMPLE_QUESTION_SHEET, SAMPLE_QUESTION_SHEET, SAMPLE_QUESTION_SHEET)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import com.mashup.dojo.domain.ImageId
import com.mashup.dojo.domain.Question
import com.mashup.dojo.domain.QuestionId
import com.mashup.dojo.domain.QuestionSet
import com.mashup.dojo.domain.QuestionSheet
import com.mashup.dojo.domain.QuestionType
import com.mashup.dojo.service.MemberService
import com.mashup.dojo.service.QuestionService
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
Expand All @@ -29,12 +31,15 @@ interface QuestionUseCase {
fun createQuestionSet(): QuestionSet

fun createCustomQuestionSet(command: CreateQuestionSetCommand): QuestionSet

fun createQuestionSheet(): List<QuestionSheet>
}

@Component
@Transactional(readOnly = true)
class DefaultQuestionUseCase(
private val questionService: QuestionService,
private val memberService: MemberService,
) : QuestionUseCase {
override fun create(command: QuestionUseCase.CreateCommand): Question {
return questionService.createQuestion(
Expand All @@ -60,4 +65,10 @@ class DefaultQuestionUseCase(
override fun createCustomQuestionSet(command: QuestionUseCase.CreateQuestionSetCommand): QuestionSet {
return questionService.createQuestionSet(command.questionIdList, command.publishedAt)
}

override fun createQuestionSheet(): List<QuestionSheet> {
val currentQuestionSet = questionService.getCurrentQuestionSet()
val allMemberRecords = memberService.findAllMember()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QuestionSet ์—์„œ Question Id ๋“ค์„ ์ด์šฉํ•ด์„œ Question ๋ณ„ QuestionType ์กฐํšŒํ•ด์˜ค๊ณ 
MemberService ์—์„œ MemberId ์™€ QuestionType ์„ ๋ฐ›์•„์„œ ํ›„๋ณด์ž๋ฅผ 4~8๋ช… ๋ฝ‘์•„์˜ค๊ณ 
Service Layer ์—์„œ๋Š” ๋‹ค๋ฅธ ์„œ๋น„์Šค ๋ ˆ์ด์–ด ํ˜ธ์ถœ์ด ์–ด๋ ต๋‹ค๋ณด๋‹ˆ,
์œ ์ €๋ณ„ ์–ด๋–ค ํ›„๋ณด์ž๊ฐ€ ์žˆ๋Š” ์ง€ ํ›„๋ณด์ž๋„ ๋งž์ถฐ์„œ questionService.createQuestionSheets() ์— ๋„˜๊ฒจ์ค˜์•ผ ํ•  ๊ฒƒ ๊ฐ™์€๋ฐ ์–ด๋–ค๊ฐ€์š”?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋ง์”€ํ•˜์‹  ๋กœ์ง์„ QuestionService์—์„œ

override fun createQuestionSheets(
    questionSet: QuestionSet?,
    members: List<Member>,
): List<QuestionSheet> {
    /**
     * TODO:
     * target : members
     * question : QuestionSet
     * candidate : member.candidate()
     *
     * - make friend logic, get Candidate logic
     * - cache put -> QuestionSet and return
     * - Temporarily set to create for all members, discuss details later
     */
    return LIST_SAMPLE_QUESTION_SHEET
}

์œ„์™€ ๊ฐ™์ด Candidate์™€ Question์„ QuestionService์—์„œ ์ƒ์„ฑํ•˜๋ คํ–ˆ๋Š”๋ฐ, QuestionUseCase์—์„œ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„๊นŒ์š”??

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋…ผ์˜ ํ›„ Candidate ๋ณ„๋กœ Domain ์œผ๋กœ ๋บ„ ๊ฒƒ์œผ๋กœ ๊ณ„ํšํ•˜์˜€์Šต๋‹ˆ๋‹ค.

return questionService.createQuestionSheets(currentQuestionSet, allMemberRecords)
}
}
Loading