Skip to content

Commit

Permalink
6/24 배포 작업 (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
cookienc authored Jun 24, 2024
1 parent d00ac05 commit c95749c
Show file tree
Hide file tree
Showing 20 changed files with 368 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/prod-pull-request-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ jobs:
- name: Docker Compose
run: |
~/backend/deploy.sh
~/backend/zero-downtime-deploy.sh
docker container prune -f
sudo docker image prune -af
2 changes: 1 addition & 1 deletion secrets
4 changes: 2 additions & 2 deletions src/main/kotlin/backend/itracker/config/AuditConfig.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package backend.itracker.config

import org.springframework.context.annotation.Configuration
import org.springframework.data.jpa.repository.config.EnableJpaAuditing
import org.springframework.stereotype.Component

@Component
@Configuration
@EnableJpaAuditing
class AuditConfig

43 changes: 43 additions & 0 deletions src/main/kotlin/backend/itracker/crawl/result/CrawlResult.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package backend.itracker.crawl.result

import backend.itracker.crawl.common.BaseEntity
import backend.itracker.crawl.service.CrawlTargetCategory
import jakarta.persistence.Entity

@Entity
class CrawlResult(

var airpods: Int = 0,
var ipad: Int = 0,
var iphone: Int = 0,
var mac: Int = 0,
var macbook: Int = 0,
var appleWatch: Int = 0,
id: Long = 0L,
) : BaseEntity(id) {

override fun toString(): String {
return "CrawlResult(airpods=$airpods, ipad=$ipad, iphone=$iphone, mac=$mac, macbook=$macbook, appleWatch=$appleWatch)"
}

fun update(result: CrawlResult) {
this.airpods += result.airpods
this.ipad += result.ipad
this.iphone += result.iphone
this.mac += result.mac
this.macbook += result.macbook
this.appleWatch += result.appleWatch
}

companion object {
fun from(crawlCategory: CrawlTargetCategory): CrawlResult =
when (crawlCategory) {
CrawlTargetCategory.MACBOOK -> CrawlResult(macbook = 1)
CrawlTargetCategory.IPAD -> CrawlResult(ipad = 1)
CrawlTargetCategory.APPLE_WATCH -> CrawlResult(appleWatch = 1)
CrawlTargetCategory.MAC -> CrawlResult(mac = 1)
CrawlTargetCategory.AIRPODS -> CrawlResult(airpods = 1)
CrawlTargetCategory.IPHONE -> CrawlResult(iphone = 1)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package backend.itracker.crawl.result.repository

import backend.itracker.crawl.result.CrawlResult
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.jpa.repository.Query
import java.time.LocalDateTime

interface CrawlResultRepository : JpaRepository<CrawlResult, Long> {

@Query("""
select cr
from CrawlResult cr
where cr.createdAt between :today and :tomorrow
""")
fun findByCreatedAtBetween(today: LocalDateTime, tomorrow: LocalDateTime) : List<CrawlResult>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package backend.itracker.crawl.service

import backend.itracker.crawl.result.CrawlResult
import backend.itracker.crawl.result.repository.CrawlResultRepository
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime

@Transactional
@Service
class CrawlResultService(
private val crawlResultRepository: CrawlResultRepository
) {

fun updateCrawlResult(crawlCategory: CrawlTargetCategory) {
val today = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0)
val results = crawlResultRepository.findByCreatedAtBetween(today, today.plusDays(1L))

if (results.isEmpty()) {
crawlResultRepository.save(CrawlResult.from(crawlCategory))
return
}

val latest = results.last()
latest.update(CrawlResult.from(crawlCategory))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package backend.itracker.schedule.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.task.TaskExecutor
import org.springframework.scheduling.annotation.EnableAsync
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import java.util.concurrent.Executor

private const val THREAD_POOL_SIZE = 2
private const val MAX_POOL_SIZE = 4
Expand All @@ -15,13 +15,14 @@ private const val QUEUE_CAPACITY = 4
class AsyncConfig {

@Bean
fun taskExecutor(): Executor {
fun taskExecutor(): TaskExecutor {
val taskExecutor = ThreadPoolTaskExecutor()
taskExecutor.setThreadNamePrefix("Async-Schedule-")
taskExecutor.setThreadNamePrefix("Async-itracker-")
taskExecutor.corePoolSize = THREAD_POOL_SIZE
taskExecutor.maxPoolSize = MAX_POOL_SIZE
taskExecutor.queueCapacity = QUEUE_CAPACITY
taskExecutor.initialize()
taskExecutor.setWaitForTasksToCompleteOnShutdown(true)
taskExecutor.setAwaitTerminationSeconds(180)
return taskExecutor
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package backend.itracker.schedule.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.TaskScheduler
import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler

@Configuration
@EnableScheduling
class SchedulingConfig {

@Bean
fun taskScheduler(): TaskScheduler {
val threadPoolTaskScheduler = ThreadPoolTaskScheduler()
threadPoolTaskScheduler.poolSize = 1
threadPoolTaskScheduler.setThreadNamePrefix("Scheduling-itracker-")
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true)
threadPoolTaskScheduler.setAwaitTerminationSeconds(180)
return threadPoolTaskScheduler
}
}

Original file line number Diff line number Diff line change
@@ -1,9 +0,0 @@
package backend.itracker.schedule.config

import org.springframework.scheduling.annotation.EnableScheduling
import org.springframework.stereotype.Component

@Component
@EnableScheduling
class ShedulingConfig

Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ class ScheduleController(
@Async
@PostMapping("/api/v1/schedule/update")
fun manualCrawl(@RequestParam category: CrawlTargetCategory) {
when (category) {
CrawlTargetCategory.MACBOOK -> crawlSchedulerService.crawlMacbook()
CrawlTargetCategory.IPAD -> crawlSchedulerService.crawlIpad()
CrawlTargetCategory.APPLE_WATCH -> crawlSchedulerService.crawlAppleWatch()
CrawlTargetCategory.MAC -> crawlSchedulerService.crawlMac()
CrawlTargetCategory.AIRPODS -> crawlSchedulerService.crawlAirPods()
CrawlTargetCategory.IPHONE -> crawlSchedulerService.crawlIphone()
}
crawlSchedulerService.crawlManual(category)
}
}
Original file line number Diff line number Diff line change
@@ -1,90 +1,28 @@
package backend.itracker.schedule.service

import backend.itracker.crawl.airpods.service.AirPodsService
import backend.itracker.crawl.ipad.service.IpadService
import backend.itracker.crawl.iphone.service.IphoneService
import backend.itracker.crawl.mac.service.MacService
import backend.itracker.crawl.macbook.service.MacbookService
import backend.itracker.crawl.service.CrawlService
import backend.itracker.crawl.watch.service.AppleWatchService
import io.github.oshai.kotlinlogging.KotlinLogging
import backend.itracker.crawl.service.CrawlTargetCategory
import backend.itracker.schedule.service.schedulers.SchedulerComposite
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Component
import kotlin.time.measureTime

private const val CRAWLING_TIME = "0 0 3 * * *"
private const val CRAWLING_TIME = "30 31 17 * * *"
private const val TIME_ZONE = "Asia/Seoul"

private val logger = KotlinLogging.logger {}
private val CRAWL_TARGETS = CrawlTargetCategory.entries

@Component
class CrawlSchedulerService(
private val crawlService: CrawlService,
private val macbookService: MacbookService,
private val ipadService: IpadService,
private val appleWatchService: AppleWatchService,
private val macService: MacService,
private val airPodsService: AirPodsService,
private val iphoneService: IphoneService
private val crawlers: SchedulerComposite,
) {

@Scheduled(cron = CRAWLING_TIME, zone = TIME_ZONE)
fun crawlMacbook() {
logger.info { "맥북 크롤링 시작. " }
val times = measureTime {
val macbooks = crawlService.crawlMacbook()
macbookService.saveAll(macbooks)
}
logger.info { "맥북 크롤링 끝. 시간: $times" }
}

@Scheduled(cron = CRAWLING_TIME, zone = TIME_ZONE)
fun crawlIpad() {
logger.info { "아이패드 크롤링 시작. " }
val times = measureTime {
val ipads = crawlService.crawlIpad()
ipadService.saveAll(ipads)
}
logger.info { "아이패드 크롤링 끝. 시간: $times" }
}

@Scheduled(cron = CRAWLING_TIME, zone = TIME_ZONE)
fun crawlAppleWatch() {
logger.info { "애플워치 크롤링 시작. " }
val times = measureTime {
val appleWatches = crawlService.crawlAppleWatch()
appleWatchService.saveAll(appleWatches)
}
logger.info { "애플워치 크롤링 끝. 시간: $times" }
}

@Scheduled(cron = CRAWLING_TIME, zone = TIME_ZONE)
fun crawlMac() {
logger.info { "맥 크롤링 시작. " }
val times = measureTime {
val macs = crawlService.crawlMac()
macService.saveAll(macs)
}
logger.info { "맥 크롤링 끝. 시간: $times" }
}

@Scheduled(cron = CRAWLING_TIME, zone = TIME_ZONE)
fun crawlAirPods() {
logger.info { "에어팟 크롤링 시작. " }
val times = measureTime {
val airPods = crawlService.crawlAirPods()
airPodsService.saveAll(airPods)
}
logger.info { "에어팟 크롤링 끝. 시간: $times" }
fun crawlManual(category: CrawlTargetCategory) {
crawlers.getScheduler(category).doSchedule()
}

@Scheduled(cron = CRAWLING_TIME, zone = TIME_ZONE)
fun crawlIphone() {
logger.info { "아이폰 크롤링 시작. " }
val times = measureTime {
val iphones = crawlService.crawlIphone()
iphoneService.saveAll(iphones)
fun scheduleCrawl() {
CRAWL_TARGETS.forEach {
crawlManual(it)
}
logger.info { "아이폰 크롤링 끝. 시간: $times" }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package backend.itracker.schedule.service.schedulers

import backend.itracker.crawl.service.CrawlResultService
import backend.itracker.crawl.service.CrawlService
import backend.itracker.crawl.service.CrawlTargetCategory

abstract class Schedulable(
private val crawlResultService: CrawlResultService,
private val crawlService: CrawlService,
) {

abstract fun supports(): CrawlTargetCategory

abstract fun doSchedule()
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package backend.itracker.schedule.service.schedulers

import backend.itracker.crawl.service.CrawlTargetCategory
import org.springframework.stereotype.Component

@Component
class SchedulerComposite(
private val schedulables: Set<Schedulable>
) {

private val schedulers = schedulables.associateBy { it.supports() }

fun getScheduler(crawlTargetCategory: CrawlTargetCategory): Schedulable {
return schedulers[crawlTargetCategory] ?: throw IllegalStateException("해당하는 스케쥴러가 없습니다. $crawlTargetCategory")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package backend.itracker.schedule.service.schedulers.airpods

import backend.itracker.crawl.airpods.service.AirPodsService
import backend.itracker.crawl.service.CrawlResultService
import backend.itracker.crawl.service.CrawlService
import backend.itracker.crawl.service.CrawlTargetCategory
import backend.itracker.schedule.service.schedulers.Schedulable
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Component
import kotlin.time.measureTime

private val logger = KotlinLogging.logger {}

@Component
class AirpodsScheduler(
private val airPodsService: AirPodsService,
private val crawlResultService: CrawlResultService,
private val crawlService: CrawlService,
) : Schedulable(crawlResultService, crawlService) {

override fun supports(): CrawlTargetCategory {
return CrawlTargetCategory.AIRPODS
}

override fun doSchedule() {
logger.info { "에어팟 크롤링 시작. " }
val times = measureTime {
val airPods = crawlService.crawlAirPods()
airPodsService.saveAll(airPods)
}
crawlResultService.updateCrawlResult(CrawlTargetCategory.AIRPODS)
logger.info { "에어팟 크롤링 끝. 시간: $times" }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package backend.itracker.schedule.service.schedulers.ipad

import backend.itracker.crawl.ipad.service.IpadService
import backend.itracker.crawl.service.CrawlResultService
import backend.itracker.crawl.service.CrawlService
import backend.itracker.crawl.service.CrawlTargetCategory
import backend.itracker.schedule.service.schedulers.Schedulable
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Component
import kotlin.time.measureTime

private val logger = KotlinLogging.logger {}

@Component
class IpadScheduler(
private val ipadService: IpadService,
private val crawlResultService: CrawlResultService,
private val crawlService: CrawlService,
) : Schedulable(crawlResultService, crawlService) {

override fun supports(): CrawlTargetCategory {
return CrawlTargetCategory.IPAD
}

override fun doSchedule() {
logger.info { "아이패드 크롤링 시작. " }
val times = measureTime {
val ipads = crawlService.crawlIpad()
ipadService.saveAll(ipads)
}
crawlResultService.updateCrawlResult(CrawlTargetCategory.IPAD)
logger.info { "아이패드 크롤링 끝. 시간: $times" }
}
}
Loading

0 comments on commit c95749c

Please sign in to comment.