Skip to content

Instantly share code, notes, and snippets.

@eungju
Last active April 12, 2018 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eungju/fcee780c4dc6135bdccfe49f7a7d1c72 to your computer and use it in GitHub Desktop.
Save eungju/fcee780c4dc6135bdccfe49f7a7d1c72 to your computer and use it in GitHub Desktop.
Timeout CircuitBreaker
interface CircuitBreakerMetrics {
fun executionCompleted(name: String, latency: Double) = Unit
}
import io.prometheus.client.Collector
import io.prometheus.client.Histogram
class PrometheusCircuitBreakerMetrics : CircuitBreakerMetrics, Collector() {
override fun collect(): MutableList<MetricFamilySamples> = callLatencyHistogram.collect()
private val callLatencyHistogram = Histogram.build()
.namespace("resilence4j")
.subsystem("circuitbreaker")
.name("call_latency_seconds")
.labelNames("name")
.help("call latency in seconds")
.create()
override fun executionCompleted(name: String, latency: Double) {
callLatencyHistogram.labels(name).observe(latency)
}
}
import io.github.resilience4j.circuitbreaker.CircuitBreaker
import java.time.Duration
import java.util.concurrent.TimeoutException
class TimeoutCircuitBreaker(
private val circuitBreaker: CircuitBreaker,
private val timeout: Duration,
private val metrics: CircuitBreakerMetrics
) : CircuitBreaker by circuitBreaker {
private val NANOS_PER_SECOND = Duration.ofSeconds(1).toNanos().toDouble()
private val timeoutInNanos = timeout.toNanos()
override fun onError(durationInNanos: Long, throwable: Throwable) {
metrics.executionCompleted(name, durationInNanos / NANOS_PER_SECOND)
circuitBreaker.onError(durationInNanos, throwable)
}
override fun onSuccess(durationInNanos: Long) {
if (durationInNanos > timeoutInNanos) {
onError(durationInNanos, TimeoutException("An execution of $name takes ${durationInNanos}ns"))
} else {
metrics.executionCompleted(name, durationInNanos / NANOS_PER_SECOND)
circuitBreaker.onSuccess(durationInNanos)
}
}
}
import io.github.resilience4j.circuitbreaker.CircuitBreaker
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry
import java.time.Duration
import java.util.function.Supplier
class TimeoutCircuitBreakerRegistry(
private val circuitBreakerRegistry: CircuitBreakerRegistry,
private val defaultTimeout: Duration,
private val metrics: CircuitBreakerMetrics
) : CircuitBreakerRegistry by circuitBreakerRegistry {
fun decorate(circuitBreaker: CircuitBreaker, timeout: Duration) =
TimeoutCircuitBreaker(circuitBreaker, timeout, metrics)
fun circuitBreaker(name: String, timeout: Duration): CircuitBreaker =
decorate(circuitBreakerRegistry.circuitBreaker(name), timeout)
fun circuitBreaker(name: String, circuitBreakerConfig: CircuitBreakerConfig, timeout: Duration): CircuitBreaker =
decorate(circuitBreakerRegistry.circuitBreaker(name, circuitBreakerConfig), timeout)
fun circuitBreaker(
name: String,
circuitBreakerConfigSupplier: Supplier<CircuitBreakerConfig>,
timeout: Duration
): CircuitBreaker =
decorate(circuitBreakerRegistry.circuitBreaker(name, circuitBreakerConfigSupplier), timeout)
override fun circuitBreaker(name: String): CircuitBreaker =
circuitBreaker(name, defaultTimeout)
override fun circuitBreaker(name: String, circuitBreakerConfig: CircuitBreakerConfig): CircuitBreaker =
circuitBreaker(name, circuitBreakerConfig, defaultTimeout)
override fun circuitBreaker(
name: String,
circuitBreakerConfigSupplier: Supplier<CircuitBreakerConfig>
): CircuitBreaker =
circuitBreaker(name, circuitBreakerConfigSupplier, defaultTimeout)
companion object {
@JvmStatic
fun ofDefaults() = TimeoutCircuitBreakerRegistry(
CircuitBreakerRegistry.ofDefaults(),
Duration.ofSeconds(1), object : CircuitBreakerMetrics {})
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment