A circuit-breaker implementation with Akka.Actor.
CircuitBreaker provides stability and resilience.
write dependency in your build.sbt.
libraryDependencies += "net.petitviolet" %% "supervisor" % "<latest version>"
// libraryDependencies += "net.petitviolet" % "supervisor_2.12" % "<latest version>"
I call circuit-breaker as Supervisor.
You can use it just like an ActorRef.
import net.petitviolet.supervisor._
import scala.concurrent.duration._
// create Supervisor instance
val supervisorActor: ActorRef = system.actorOf(Supervisor.props(
maxFailCount = 2,
runTimeout = 1000.milliseconds,
resetWait = 3000.milliseconds
))
// other ActorRef
val actorRef = system.actorOf(Props[SomeYourActor])
// supervising asynchronous procedure which is enveloped by `Execute`
supervisorActor ? Execute(actorRef ? Message("1")) onComplete {
case Success(x) =>
println(s"result =>$x")
case Failure(t) =>
t.printStackTrace()
}Supervisor needs 3 values.
maxFailCount- if failure count gets more than equal this limit,
Supervisorstate getsOpen
- if failure count gets more than equal this limit,
runTimeout- wait time for asynchronous process by
Supervisor
- wait time for asynchronous process by
resetWait- when
Supervisorstate isOpenand past this duration, its state getsHalf-Open
- when
import net.petitviolet.supervisor._
import scala.concurrent.duration._
// create Supervisor instance
val supervisorActor: ActorRef = system.actorOf(Supervisor.props(
maxFailCount = 2,
runTimeout = 1000.milliseconds,
resetWait = 3000.milliseconds
))Using Typesafe Config library.
In some conf file, for example application.conf, write like below.
supervisor {
max-fail-count = 2
run-timeout = 1000
reset-wait = 3000
}
The key supervisor is modifiable, but others are not.
val config = ConfigFactory.load().getConfig("supervisor")
val supervisorActor: ActorRef = system.actorOf(Supervisor.props(config))ActorRef instance of Supervisor supervises asynchronous procedures.
When you wrap your scala.concurrent.Future instance in Execute and tell or ask to it, it works as a CircuitBreaker.
// other ActorRef for example to create Future.
val actorRef = system.actorOf(Props[SomeYourActor])
// supervising asynchronous procedure which is enveloped by `Execute`.
// Of cource you can use `tell` instead of `ask`, when you do not need result of Future.
supervisorActor ? Execute(actorRef ? Message("1")) onComplete {
case Success(x) =>
println(s"result =>$x")
case Failure(t) =>
t.printStackTrace()
}There are the same 3 states as CircuitBreaker. Simple description of each states is below.
- Close
- normal state.
Supervisortry to given process done normally with waitingrunTimeoutduration.
- Open
- Aborting
Future. - When the state is Close and the count of
FuturegetsFailureor exceededrunTimeout, it's state gets Open.
- Aborting
- Half-Open
- on the way of it's state to Close from Open.
- It's state is Open and past
resetWaitduration, it gets Half-Open.
- It's state is Open and past
- It make only 1 try, when
Success, gets Close, otherwise whenFailure, gets Open.
- on the way of it's state to Close from Open.