【发布时间】:2022-11-17 20:22:57
【问题描述】:
我正在努力使用 spring boot @Cacheable 和 ehcache 在两种方法上正确使用协程来处理缓存:
- 使用 webclient 调用另一个服务:
suspend fun getDeviceOwner(correlationId: String, ownerId: String): DeviceOwner{ webClient .get() .uri(uriProvider.provideUrl()) .header(CORRELATION_ID, correlationId) .retrieve() .onStatus(HttpStatus::isError) {response -> Mono.error( ServiceCallExcpetion("Call failed with: ${response.statusCode()}") ) }.awaitBodyOrNull() ?: throw ServiceCallExcpetion("Call failed with - response is null.") }- 使用 r2dbc 调用数据库
suspend fun findDeviceTokens(ownerId: UUID, deviceType: String) { //CoroutineCrudRepository.findTokens }似乎对我有用的是来自:
suspend fun findTokens(data: Data): Collection<String> = coroutineScope { val ownership = async(Dispatchers.IO, CoroutineStart.LAZY) { service.getDeviceOwner(data.nonce, data.ownerId) }.await() val tokens = async(Dispatchers.IO, CoroutineStart.LAZY) {service.findDeviceTokens(ownership.ownerId, ownership.ownershipType)} tokens.await() }@Cacheable(value = ["ownerCache"], key = "#ownerId") fun getDeviceOwner(correlationId: String, ownerId: String)= runBlocking(Dispatchers.IO) { //webClientCall }@Cacheable("deviceCache") override fun findDeviceTokens(ownerId: UUID, deviceType: String) = runBlocking(Dispatchers.IO) { //CoroutineCrudRepository.findTokens }但是从我正在阅读的内容来看,使用 runBlocking 并不是一个好习惯。 https://kotlinlang.org/docs/coroutines-basics.html#your-first-coroutine 它会阻塞主线程还是父协程指定的线程?
我也试过
@Cacheable(value = ["ownerCache"], key = "#ownerId") fun getDeviceOwnerAsync(correlationId: String, ownerId: String) = GlobalScope.async(Dispatchers.IO, CoroutineStart.LAZY) { //webClientCall }@Cacheable("deviceCache") override fun findDeviceTokensAsync(ownerId: UUID, deviceType: String) = GlobalScope.async(Dispatchers.IO, CoroutineStart.LAZY) { //CoroutineCrudRepository.findTokens }两者都是从挂起的函数中调用的,没有任何额外的
coroutineScope {}和 async{}suspend fun findTokens(data: Data): Collection<String> = service.getDeviceOwnerAsync(data.nonce,data.ownerId).await() .let{service.findDeviceTokensAsync(it.ownerId, it.ownershipType).await()}我读到使用 GlobalScope 不是一个好习惯,因为当某些东西卡住或长时间响应时可能会无休止地运行这个协程(用非常简单的话)。同样在这种方法中,使用 GlobalScope,当我测试负面场景并且外部 ms 调用导致 404(故意)时,结果没有存储在缓存中(正如我所除外),但是对于失败的 CoroutineCrudRepository.findTokens 调用(抛出异常)延迟值是缓存这不是我想要的。存储失败的执行结果与 runBlocking 无关。
我也试过
@Cacheable("deviceCache", unless = "#result.isCompleted == true && #result.isCancelled == true")但它似乎也不像我想象的那样有效。您能否建议最好的协程方法和正确的异常处理以与 spring boot 缓存集成,它只会在非失败调用时将值存储在缓存中?
【问题讨论】:
标签: spring-boot caching kotlin-coroutines