commit
4eb433d372
|
@ -26,6 +26,7 @@ repositories {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation("org.redisson:redisson-spring-data-27:3.19.2")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-aop")
|
implementation("org.springframework.boot:spring-boot-starter-aop")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||||
implementation("org.springframework.boot:spring-boot-starter-data-redis")
|
implementation("org.springframework.boot:spring-boot-starter-data-redis")
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package kr.co.vividnext.sodalive.configs
|
package kr.co.vividnext.sodalive.configs
|
||||||
|
|
||||||
|
import org.redisson.Redisson
|
||||||
|
import org.redisson.api.RedissonClient
|
||||||
|
import org.redisson.config.Config
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.cache.annotation.EnableCaching
|
import org.springframework.cache.annotation.EnableCaching
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
|
@ -26,6 +29,19 @@ class RedisConfig(
|
||||||
@Value("\${spring.redis.port}")
|
@Value("\${spring.redis.port}")
|
||||||
private val port: Int
|
private val port: Int
|
||||||
) {
|
) {
|
||||||
|
@Bean(destroyMethod = "shutdown")
|
||||||
|
fun redissonClient(): RedissonClient {
|
||||||
|
val config = Config()
|
||||||
|
config.useSingleServer()
|
||||||
|
.setAddress("rediss://$host:$port")
|
||||||
|
.setSslEnableEndpointIdentification(true)
|
||||||
|
.setSslTruststore(null)
|
||||||
|
.setDnsMonitoringInterval(30000)
|
||||||
|
.setConnectionMinimumIdleSize(0)
|
||||||
|
.setConnectionPoolSize(5)
|
||||||
|
return Redisson.create(config)
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun redisConnectionFactory(): RedisConnectionFactory {
|
fun redisConnectionFactory(): RedisConnectionFactory {
|
||||||
val clientConfiguration = LettuceClientConfiguration.builder()
|
val clientConfiguration = LettuceClientConfiguration.builder()
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
package kr.co.vividnext.sodalive.scheduler
|
package kr.co.vividnext.sodalive.scheduler
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.content.AudioContentService
|
import kr.co.vividnext.sodalive.content.AudioContentService
|
||||||
|
import org.redisson.api.RedissonClient
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler
|
||||||
import org.springframework.scheduling.support.CronTrigger
|
import org.springframework.scheduling.support.CronTrigger
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import java.util.concurrent.ScheduledFuture
|
import java.util.concurrent.ScheduledFuture
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.annotation.PostConstruct
|
import javax.annotation.PostConstruct
|
||||||
import javax.annotation.PreDestroy
|
import javax.annotation.PreDestroy
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class AudioContentReleaseScheduledTask(
|
class AudioContentReleaseScheduledTask(
|
||||||
private val audioContentService: AudioContentService,
|
private val audioContentService: AudioContentService,
|
||||||
|
private val redissonClient: RedissonClient,
|
||||||
@Qualifier("audioContentReleaseScheduler") private val audioContentReleaseScheduler: ThreadPoolTaskScheduler
|
@Qualifier("audioContentReleaseScheduler") private val audioContentReleaseScheduler: ThreadPoolTaskScheduler
|
||||||
) {
|
) {
|
||||||
private var scheduledTask: ScheduledFuture<*>? = null
|
private var scheduledTask: ScheduledFuture<*>? = null
|
||||||
|
@ -19,7 +22,25 @@ class AudioContentReleaseScheduledTask(
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
fun release() {
|
fun release() {
|
||||||
scheduledTask = audioContentReleaseScheduler.schedule(
|
scheduledTask = audioContentReleaseScheduler.schedule(
|
||||||
{ audioContentService.releaseContent() },
|
{
|
||||||
|
val lockName = "lock:audioContentRelease"
|
||||||
|
val lock = redissonClient.getLock(lockName)
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 5초 동안 락을 시도하고, Watchdog 활성화 (-1 설정)
|
||||||
|
if (lock.tryLock(5, -1, TimeUnit.SECONDS)) {
|
||||||
|
println("acquired : $lockName")
|
||||||
|
audioContentService.releaseContent()
|
||||||
|
} else {
|
||||||
|
println("Failed to acquire lock : $lockName")
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (lock.isHeldByCurrentThread) {
|
||||||
|
lock.unlock()
|
||||||
|
println("release : $lockName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
CronTrigger("0 0/15 * * * *")
|
CronTrigger("0 0/15 * * * *")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue