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,
Supervisor
state 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
Supervisor
state isOpen
and 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.
Supervisor
try to given process done normally with waitingrunTimeout
duration.
- Open
- Aborting
Future
. - When the state is Close and the count of
Future
getsFailure
or 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
resetWait
duration, 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.