我有一个通过 REST 调用依赖项的服务。服务和依赖是微服务架构的一部分,所以我想使用弹性模式。我的目标是:
- 当依赖关系陷入困境时,有一个断路器来保护它
- 限制呼叫可以运行的时间。该服务具有 SLA,并且必须在特定时间内回答。在超时时,我们使用回退值。
- 限制对依赖项的并发调用数。通常调用率很低,响应速度很快,但我们希望保护依赖关系免受服务内部的突发和排队请求。
以下是我当前的代码。它可以工作,但理想情况下我想使用TimeLimiter
andBulkhead
类,因为它们似乎是为了一起工作而构建的。
我怎样才能写得更好?
@Component
class FooService(@Autowired val circuitBreakerRegistry: CircuitBreakerRegistry)
{
...
// State machine to take load off the dependency when slow or unresponsive
private val circuitBreaker = circuitBreakerRegistry
.circuitBreaker("fooService")
// Limit parallel requests to dependency
private var semaphore = Semaphore(maxParallelRequests)
// The protected function
private suspend fun makeHttpCall(customerId: String): Boolean {
val client = webClientProvider.getCachedWebClient(baseUrl)
val response = client
.head()
.uri("/the/request/url")
.awaitExchange()
return when (val status = response.rawStatusCode()) {
200 -> true
204 -> false
else -> throw Exception(
"Foo service responded with invalid status code: $status"
)
}
}
// Main function
suspend fun isFoo(someId: String): Boolean {
try {
return circuitBreaker.executeSuspendFunction {
semaphore.withPermit {
try {
withTimeout(timeoutMs) {
makeHttpCall(someId)
}
} catch (e: TimeoutCancellationException) {
// This exception has to be converted because
// the circuit-breaker ignores CancellationException
throw Exception("Call to foo service timed out")
}
}
}
} catch (e: CallNotPermittedException) {
logger.error { "Call to foo blocked by circuit breaker" }
} catch (e: Exception) {
logger.error { "Exception while calling foo service: ${e.message}" }
}
// Fallback
return true
}
}
理想情况下,我想写一些类似于Flows的文档描述的东西:
// Main function
suspend fun isFoo(someId: String): Boolean {
return monoOf(makeHttpCall(someId))
.bulkhead(bulkhead)
.timeLimiter(timeLimiter)
.circuitBreaker(circuitBreaker)
}