mirror of https://github.com/usbharu/Hideout.git
feat: 同じ内容のリクエストが同時多発的に発生しない仕組みを追加
This commit is contained in:
parent
65ad6409f2
commit
ed296637d9
|
@ -0,0 +1,9 @@
|
|||
package dev.usbharu.hideout.service.ap.resource
|
||||
|
||||
import dev.usbharu.hideout.domain.model.ap.Object
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
|
||||
interface APResourceResolveService {
|
||||
suspend fun resolve(url: String, singerId: Long?): Object
|
||||
suspend fun resolve(url: String, singer: User?): Object
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package dev.usbharu.hideout.service.ap.resource
|
||||
|
||||
import dev.usbharu.hideout.domain.model.ap.Object
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.repository.UserRepository
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import kotlinx.coroutines.delay
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class APResourceResolveServiceImpl(private val httpClient: HttpClient, private val userRepository: UserRepository) :
|
||||
APResourceResolveService {
|
||||
|
||||
override suspend fun resolve(url: String, singerId: Long?): Object {
|
||||
return internalResolve(url, singerId)
|
||||
}
|
||||
|
||||
override suspend fun resolve(url: String, singer: User?): Object {
|
||||
return internalResolve(url, singer)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return wait(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
|
||||
}
|
||||
return wait(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 {
|
||||
return httpClient.get(url).body<Object>()
|
||||
}
|
||||
|
||||
private fun genCacheKey(url: String, singerId: Long?): String {
|
||||
if (singerId != null) {
|
||||
return "$url-$singerId"
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val cacheKey = ConcurrentHashMap<String, Long>()
|
||||
private val valueStore = Collections.synchronizedMap(mutableMapOf<String, Object>())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue