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

v0.1.6-Release #70

Merged
merged 2 commits into from
Dec 5, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.mjucow.eatda.scheduled

import com.mjucow.eatda.jooq.tables.Banner.BANNER
import com.mjucow.eatda.jooq.tables.records.ExpiredBannerRecord
import org.jooq.DSLContext
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import org.springframework.transaction.support.TransactionTemplate
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId

@Component
class ExpiredBannerBatchJob(
private val db: DSLContext,
private val transactionTemplate: TransactionTemplate,
) {
@Scheduled(cron = "0 0 22 * * *", zone = "Asia/Seoul") // 매일 오후 10시 동작
fun scheduleTaskUsingCronExpression() {
val now = Instant.now()
transactionTemplate.execute {
val expiredBanners = findAllExpiredBanners(now)
if (expiredBanners.isEmpty()) {
return@execute
}

expiredBannerBulkInsert(expiredBanners)

bulkDeleteBanners(expiredBanners)
}
}

private fun findAllExpiredBanners(now: Instant): List<ExpiredTargetBanner> {
return db
.select(BANNER.ID, BANNER.LINK, BANNER.IMAGE_ADDRESS, BANNER.EXPIRED_AT)
.from(BANNER)
.where(
BANNER.EXPIRED_AT.isNotNull
.and(BANNER.EXPIRED_AT.lessOrEqual(LocalDateTime.ofInstant(now, ZONE_ID)))
)
.fetch()
.into(ExpiredTargetBanner::class.java)
.toList()
}

private fun expiredBannerBulkInsert(expireTargetBanners: List<ExpiredTargetBanner>) {
val expiredBanners = expireTargetBanners.map { banner ->
ExpiredBannerRecord().apply {
this.link = banner.link
this.imageAddress = banner.imageAddress
this.expiredAt = banner.expiredAt
}
}
db.batchInsert(expiredBanners).execute()
}

private fun bulkDeleteBanners(expiredBanners: List<ExpiredTargetBanner>) {
val deletedBannerIds = expiredBanners.map { it.id }
db.deleteFrom(BANNER).where(BANNER.ID.`in`(deletedBannerIds)).execute()
}

data class ExpiredTargetBanner(
val id: Long,
val link: String,
val imageAddress: String,
val expiredAt: LocalDateTime,
)

companion object {
val ZONE_ID: ZoneId = ZoneId.of("Asia/Seoul")
}
}
17 changes: 17 additions & 0 deletions src/main/kotlin/com/mjucow/eatda/scheduled/ScheduleJobConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.mjucow.eatda.scheduled

import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.annotation.EnableScheduling

@Configuration
@EnableScheduling
class ScheduleJobConfig {
// @Bean
// fun taskScheduler(): TaskScheduler {
// val threadPoolTaskScheduler = ThreadPoolTaskScheduler().apply {
// poolSize = 5
// setThreadNamePrefix("ThreadPoolTaskScheduler")
// }
// return threadPoolTaskScheduler
// }
}
8 changes: 8 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ spring:
generate-ddl: false
hibernate:
ddl-auto: validate
task:
scheduling:
pool:
size: 1

web.resources.add-mappings: false
liquibase:
Expand Down Expand Up @@ -56,6 +60,10 @@ spring:
generate-ddl: false
hibernate:
ddl-auto: none
task:
scheduling:
pool:
size: 5

datasource:
driver-class-name: org.postgresql.Driver
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.mjucow.eatda.scheduled

import com.mjucow.eatda.domain.AbstractDataTest
import com.mjucow.eatda.domain.banner.entity.objectmother.BannerMother
import com.mjucow.eatda.jooq.tables.ExpiredBanner.EXPIRED_BANNER
import com.mjucow.eatda.jooq.tables.records.BannerRecord
import com.mjucow.eatda.jooq.tables.records.ExpiredBannerRecord
import com.mjucow.eatda.persistence.banner.BannerRepository
import org.assertj.core.api.Assertions
import org.jooq.DSLContext
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Import
import java.time.LocalDateTime
import java.util.stream.IntStream

@Import(value = [ExpiredBannerBatchJob::class])
class ExpiredBannerBatchJobTest : AbstractDataTest() {
@Autowired
lateinit var db: DSLContext

@Autowired
lateinit var bannerRepository: BannerRepository

@Autowired
lateinit var expiredBannerBatchJob: ExpiredBannerBatchJob

@DisplayName("배치할 거 없으면 따로 동작 안하기")
@Test
fun test1() {
// given

// when
expiredBannerBatchJob.scheduleTaskUsingCronExpression()

// then
val createdExpiredBanners = findAllExpiredBanner()
Assertions.assertThat(createdExpiredBanners).isEmpty()
}

@DisplayName("배치할 거 있으면 expiredBanner로 데이터 복사하기")
@Test
fun test2() {
// given
val now = LocalDateTime.now(ZONE_ID)
val expiredAt = now.minusDays(1)
val count = 3
db.batchInsert(
IntStream
.range(0, count)
.mapToObj {
BannerRecord().apply {
this.imageAddress = BannerMother.IMAGE_ADDRESS
this.link = BannerMother.LINK
this.expiredAt = expiredAt
this.createdAt = now
this.updatedAt = now
}
}.toList()
).execute()

// when
expiredBannerBatchJob.scheduleTaskUsingCronExpression()

// then
val createdExpiredBanners = findAllExpiredBanner()
Assertions.assertThat(createdExpiredBanners).hasSize(count)
Assertions.assertThat(bannerRepository.findAll()).isEmpty()
}

private fun findAllExpiredBanner(): List<ExpiredBannerRecord> {
return db.selectQuery(EXPIRED_BANNER).toList()
}

companion object {
val ZONE_ID = ExpiredBannerBatchJob.ZONE_ID
}
}