-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Circuit breaker #266
Circuit breaker #266
Conversation
For now this is incomplete since I have some questions.
Right now only now only count based sliding window is implemented but I wanted to discuss those questions right away. With time based sliding windows I think that background loop evicting older entries from queue similar to SlidingWindow RateLimiterAlgorithm should be sufficient. |
As for the questions:
|
Answer based on what is available in pekko/akka, monix, rezilience (zio). circuit (cats-effect) and polly(C#)
Monix, circuit and Pekko/Akka works exactly the same. They count failures (or slow calls) in a row not a rate based on window. Then wait before going to halfOpen and then deciding based on one operation result. Plus the wait duration before transitioning to halfOpen is configured as backoff. rezilience provides maxFailures in a row just like monix and also count based sliding window. It also supports different schedules for waiting before going to halfOpen state. It also allows only one call to decide if it goes back to open or close. Polly is little different but only in few cases. It provides threshold rates for sampling window of some duration. As I understand it in effect means sliding window(But maybe it is simpler and works just like fixed window). It also support minimum number of calls to be able trip in a sample. It also allows for dynamically determining break duration before switching to halfOpen.It also provide ability to set state manually and reading current state through CircuitBreakerStateProvider. Zio, resilience4j and rezilience also provides ability to consume different events like state changes or metrics. |
Good analysis, thanks :) So basing on that, what design would you propose? What would be the configuration options, and the algorithm of transferring between closed/ho/open states? Not sure if we need both count-based and windowed variants - isn't the count-based variant a windowed variant, but with window duration = Inf? |
There is difference that if we would just treat count based as sliding window with Inf we would always have to count all results. Window size defines how many n last operation we want to include in metrics. I wanted to move all state machine logic to base trait and only difference between implementations would be how we calculate metrics. If we leave both variants we can have all functionalities (maybe apart from ability to consume events). Giving proper arguments we can mimic pekko and monix behavior exactly. I am only debating if we would want to support any Infinite schedule when it comes to those durations, but I would want to have proper implementation of all other functionalities before that, then see if it fits. |
But in a count-based approach, you're counting all results anyway? |
Yeah, but callResults is a very basic implementation of CircularBuffer so we count only on max n call results and don't hold in memory more results than we need. The writeIndex is increment during registration of result. |
I changed calculating state change to be pure function. Added docs in code and some tests for the state machine. I will add more tests especially testing if schedules and timeout for state changes work properly. I also need to add docs, I think in this case some kind of diagram would be helpful to understand how this work. |
Also seems like CI is broken because of deprecation of |
Let's fix it then, in a separate PR then :) |
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
core/src/main/scala/ox/resilience/CircuitBreakerStateMachine.scala
Outdated
Show resolved
Hide resolved
I think I addressed everything in this round of comments :). Turns out there were also typos in comments and tests, so I corrected them. |
Great, looking :) |
This draft implements CricuitBreaker with features based on that are provided in breaker from resilience4j.
Those features, for count based window (last n operations):
Things that are not implemented in here but are in resilience4j.