mirror of https://github.com/usbharu/Hideout.git
feat: CacheManagerを使用した実装に切り替え
This commit is contained in:
parent
52b609bac8
commit
1fef97c8ce
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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>())
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue