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-core:0.6.0")
|
||||||
implementation("org.drewcarlson:kjob-mongo: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")
|
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.*
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class APResourceResolveServiceImpl(
|
class APResourceResolveServiceImpl(
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
|
private val cacheManager: CacheManager,
|
||||||
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
||||||
) :
|
) :
|
||||||
APResourceResolveService {
|
APResourceResolveService {
|
||||||
|
@ -34,31 +31,19 @@ class APResourceResolveServiceImpl(
|
||||||
private suspend fun internalResolve(url: String, singerId: Long?): Object {
|
private suspend fun internalResolve(url: String, singerId: Long?): Object {
|
||||||
|
|
||||||
val key = genCacheKey(url, singerId)
|
val key = genCacheKey(url, singerId)
|
||||||
val ifAbsent = cacheKey.putIfAbsent(key, Instant.now().toEpochMilli())
|
|
||||||
if (ifAbsent == null) {
|
cacheManager.putCache(key) {
|
||||||
val resolve = runResolve(url, singerId?.let { userRepository.findById(it) })
|
runResolve(url, singerId?.let { userRepository.findById(it) })
|
||||||
valueStore.putIfAbsent(key, resolve)
|
|
||||||
return resolve
|
|
||||||
}
|
}
|
||||||
return wait(key)
|
return cacheManager.getOrWait(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun internalResolve(url: String, singer: User?): Object {
|
private suspend fun internalResolve(url: String, singer: User?): Object {
|
||||||
val key = genCacheKey(url, singer?.id)
|
val key = genCacheKey(url, singer?.id)
|
||||||
val ifAbsent = cacheKey.putIfAbsent(key, Instant.now().toEpochMilli())
|
cacheManager.putCache(key) {
|
||||||
if (ifAbsent == null) {
|
runResolve(url, singer)
|
||||||
val resolve = runResolve(url, singer)
|
|
||||||
valueStore.putIfAbsent(key, resolve)
|
|
||||||
return resolve
|
|
||||||
}
|
}
|
||||||
return wait(key)
|
return cacheManager.getOrWait(key)
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun wait(key: String): Object {
|
|
||||||
while (valueStore.containsKey(key).not()) {
|
|
||||||
delay(1)
|
|
||||||
}
|
|
||||||
return valueStore.getValue(key) as Object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun runResolve(url: String, singer: User?): Object {
|
private suspend fun runResolve(url: String, singer: User?): Object {
|
||||||
|
@ -72,7 +57,4 @@ class APResourceResolveServiceImpl(
|
||||||
}
|
}
|
||||||
return url
|
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)
|
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)
|
||||||
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) {
|
repeat(10) {
|
||||||
awaitAll(
|
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("abcd", 0)
|
||||||
apResourceResolveService.resolve("1234", 0)
|
apResourceResolveService.resolve("1234", 0)
|
||||||
|
|
Loading…
Reference in New Issue