feat: CacheManagerを使用した実装に切り替え

This commit is contained in:
usbharu 2023-10-12 16:02:01 +09:00
parent 52b609bac8
commit 1fef97c8ce
5 changed files with 62 additions and 31 deletions

View File

@ -143,7 +143,6 @@ dependencies {
implementation("org.drewcarlson:kjob-core:0.6.0")
implementation("org.drewcarlson:kjob-mongo:0.6.0")
testImplementation("org.slf4j:slf4j-simple:2.0.7")
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1")
}

View File

@ -8,17 +8,14 @@ import dev.usbharu.hideout.repository.UserRepository
import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.coroutines.delay
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Service
import java.time.Instant
import java.util.*
import java.util.concurrent.ConcurrentHashMap
@Service
class APResourceResolveServiceImpl(
private val httpClient: HttpClient,
private val userRepository: UserRepository,
private val cacheManager: CacheManager,
@Qualifier("activitypub") private val objectMapper: ObjectMapper
) :
APResourceResolveService {
@ -34,31 +31,19 @@ class APResourceResolveServiceImpl(
private suspend fun internalResolve(url: String, singerId: Long?): Object {
val key = genCacheKey(url, singerId)
val ifAbsent = cacheKey.putIfAbsent(key, Instant.now().toEpochMilli())
if (ifAbsent == null) {
val resolve = runResolve(url, singerId?.let { userRepository.findById(it) })
valueStore.putIfAbsent(key, resolve)
return resolve
cacheManager.putCache(key) {
runResolve(url, singerId?.let { userRepository.findById(it) })
}
return wait(key)
return cacheManager.getOrWait(key)
}
private suspend fun internalResolve(url: String, singer: User?): Object {
val key = genCacheKey(url, singer?.id)
val ifAbsent = cacheKey.putIfAbsent(key, Instant.now().toEpochMilli())
if (ifAbsent == null) {
val resolve = runResolve(url, singer)
valueStore.putIfAbsent(key, resolve)
return resolve
cacheManager.putCache(key) {
runResolve(url, singer)
}
return wait(key)
}
private suspend fun wait(key: String): Object {
while (valueStore.containsKey(key).not()) {
delay(1)
}
return valueStore.getValue(key) as Object
return cacheManager.getOrWait(key)
}
private suspend fun runResolve(url: String, singer: User?): Object {
@ -72,7 +57,4 @@ class APResourceResolveServiceImpl(
}
return url
}
private val cacheKey = ConcurrentHashMap<String, Long>()
private val valueStore = Collections.synchronizedMap(mutableMapOf<String, Object>())
}

View File

@ -0,0 +1,9 @@
package dev.usbharu.hideout.service.ap.resource
import dev.usbharu.hideout.domain.model.ap.Object
interface CacheManager {
suspend fun putCache(key: String, block: suspend () -> Object)
suspend fun getOrWait(key: String): Object
}

View File

@ -0,0 +1,37 @@
package dev.usbharu.hideout.service.ap.resource
import dev.usbharu.hideout.domain.model.ap.Object
import kotlinx.coroutines.delay
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.springframework.stereotype.Service
@Service
class InMemoryCacheManager : CacheManager {
private val cacheKey = mutableSetOf<String>()
private val valueStore = mutableMapOf<String, Object>()
private val keyMutex = Mutex()
override suspend fun putCache(key: String, block: suspend () -> Object) {
val hasCache: Boolean
keyMutex.withLock {
hasCache = cacheKey.contains(key)
cacheKey.add(key)
}
if (hasCache.not()) {
val processed = block()
valueStore[key] = processed
}
}
override suspend fun getOrWait(key: String): Object {
while (valueStore.contains(key).not()) {
delay(1)
}
return valueStore.getValue(key)
}
}

View File

@ -49,7 +49,8 @@ class APResourceResolveServiceImplTest {
)
)
val apResourceResolveService = APResourceResolveServiceImpl(httpClient, userRepository, objectMapper)
val apResourceResolveService =
APResourceResolveServiceImpl(httpClient, userRepository, InMemoryCacheManager(), objectMapper)
apResourceResolveService.resolve("https", 0)
@ -83,7 +84,8 @@ class APResourceResolveServiceImplTest {
)
)
val apResourceResolveService = APResourceResolveServiceImpl(httpClient, userRepository, objectMapper)
val apResourceResolveService =
APResourceResolveServiceImpl(httpClient, userRepository, InMemoryCacheManager(), objectMapper)
apResourceResolveService.resolve("https", 0)
apResourceResolveService.resolve("https", 0)
@ -120,7 +122,8 @@ class APResourceResolveServiceImplTest {
)
)
val apResourceResolveService = APResourceResolveServiceImpl(httpClient, userRepository, objectMapper)
val apResourceResolveService =
APResourceResolveServiceImpl(httpClient, userRepository, InMemoryCacheManager(), objectMapper)
repeat(10) {
awaitAll(
@ -168,7 +171,8 @@ class APResourceResolveServiceImplTest {
)
)
val apResourceResolveService = APResourceResolveServiceImpl(httpClient, userRepository, objectMapper)
val apResourceResolveService =
APResourceResolveServiceImpl(httpClient, userRepository, InMemoryCacheManager(), objectMapper)
apResourceResolveService.resolve("abcd", 0)
apResourceResolveService.resolve("1234", 0)