pekko/akka-actor-tests/src/test/scala/akka/pattern/CircuitBreakerStressSpec.scala

87 lines
2.3 KiB
Scala
Raw Normal View History

/*
2021-01-08 17:55:38 +01:00
* Copyright (C) 2015-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.pattern
import java.util.concurrent.ThreadLocalRandom
import java.util.concurrent.TimeoutException
import scala.concurrent.Promise
import scala.concurrent.duration._
import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.Props
import akka.actor.Status.Failure
import akka.testkit.AkkaSpec
import akka.testkit.ImplicitSender
object CircuitBreakerStressSpec {
case object JobDone
case object GetResult
case class Result(doneCount: Int, timeoutCount: Int, failCount: Int, circCount: Int)
class StressActor(breaker: CircuitBreaker) extends Actor with ActorLogging with PipeToSupport {
import context.dispatcher
private var doneCount = 0
private var timeoutCount = 0
private var failCount = 0
private var circCount = 0
private def job = {
val promise = Promise[JobDone.type]()
context.system.scheduler.scheduleOnce(ThreadLocalRandom.current.nextInt(300).millisecond) {
promise.success(JobDone)
}
promise.future
}
override def receive = {
case JobDone =>
doneCount += 1
breaker.withCircuitBreaker(job).pipeTo(self)
case Failure(_: CircuitBreakerOpenException) =>
circCount += 1
breaker.withCircuitBreaker(job).pipeTo(self)
case Failure(_: TimeoutException) =>
timeoutCount += 1
breaker.withCircuitBreaker(job).pipeTo(self)
case Failure(_) =>
failCount += 1
breaker.withCircuitBreaker(job).pipeTo(self)
case GetResult =>
sender() ! Result(doneCount, timeoutCount, failCount, circCount)
}
}
}
// reproducer for issue #17415
class CircuitBreakerStressSpec extends AkkaSpec with ImplicitSender {
import CircuitBreakerStressSpec._
muteDeadLetters(classOf[AnyRef])(system)
"A CircuitBreaker" in {
val breaker = CircuitBreaker(system.scheduler, 5, 200.millisecond, 200.seconds)
val stressActors = Vector.fill(3) {
system.actorOf(Props(classOf[StressActor], breaker))
}
for (_ <- 0 to 1000; a <- stressActors) {
a ! JobDone
}
// let them work for a while
Thread.sleep(3000)
stressActors.foreach { a =>
a ! GetResult
val result = expectMsgType[Result]
result.failCount should be(0)
}
}
}