Updated on 2026-08-14

This commit is contained in:
Tangem 2024-03-12 16:18:53 +00:00
parent 567cc9541d
commit 1da2ca6d1f
4 changed files with 87 additions and 44 deletions

View file

@ -3,15 +3,21 @@ package com.tangem.data.common.cache
import com.tangem.datasource.local.cache.CacheKeysStore
import com.tangem.datasource.local.cache.model.CacheKey
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.joda.time.Duration
import org.joda.time.LocalDateTime
import timber.log.Timber
import java.util.concurrent.ConcurrentHashMap
internal class DefaultCacheRegistry(
private val cacheKeysStore: CacheKeysStore,
) : CacheRegistry {
private val mutex = Mutex()
private val mutexes = ConcurrentHashMap<String, Mutex>()
override suspend fun isExpired(key: String): Boolean {
val cacheKey = cacheKeysStore.getSyncOrNull(key) ?: return true
@ -41,27 +47,36 @@ internal class DefaultCacheRegistry(
expireIn: Duration,
block: suspend () -> Unit,
) {
val isExpired = isExpired(key) || skipCache
if (!isExpired) return
// use a separate mutexForKey for each key to avoid multiple calls block() to the same key
// also used mutex to safe create mutexForKey, otherwise it can lead to multiple calls for the same key
val mutexForKey = mutex.withLock {
mutexes.getOrPut(key) { Mutex() }
}
mutexForKey.withLock {
val isExpired = isExpired(key) || skipCache
if (!isExpired) {
return
}
try {
Timber.d("Invoke the action associated with the cache key: $key")
try {
Timber.d("Invoke the action associated with the cache key: $key")
cacheKeysStore.store(
key = CacheKey(
id = key,
updatedAt = LocalDateTime.now(),
expiresIn = expireIn,
),
)
cacheKeysStore.store(
key = CacheKey(
id = key,
updatedAt = LocalDateTime.now(),
expiresIn = expireIn,
),
)
block()
} catch (e: Throwable) {
Timber.e(e, "The action related to the cache key has failed: $key")
block()
} catch (e: Throwable) {
Timber.e(e, "The action related to the cache key has failed: $key")
invalidate(key)
invalidate(key)
throw e
throw e
}
}
}
}