#2168 - Exposing more Netty options in remtoe config
This commit is contained in:
parent
2940740c48
commit
12b9af25cf
9 changed files with 83 additions and 47 deletions
|
|
@ -6,7 +6,7 @@ package akka.pattern
|
||||||
import akka.testkit._
|
import akka.testkit._
|
||||||
import akka.util.duration._
|
import akka.util.duration._
|
||||||
import org.scalatest.BeforeAndAfter
|
import org.scalatest.BeforeAndAfter
|
||||||
import akka.dispatch.{Promise, Await, Future}
|
import akka.dispatch.{ Promise, Await, Future }
|
||||||
|
|
||||||
class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
||||||
|
|
||||||
val halfOpenLatch = new TestLatch(1)
|
val halfOpenLatch = new TestLatch(1)
|
||||||
|
|
||||||
val breaker = new CircuitBreaker(system.scheduler,5,100.millis.dilated,500.millis.dilated)
|
val breaker = new CircuitBreaker(system.scheduler, 5, 100.millis.dilated, 500.millis.dilated)
|
||||||
.onHalfOpen(halfOpenLatch.countDown())
|
.onHalfOpen(halfOpenLatch.countDown())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -28,30 +28,30 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
||||||
|
|
||||||
def unreliableCall(param: String) = {
|
def unreliableCall(param: String) = {
|
||||||
param match {
|
param match {
|
||||||
case "fail" => throw new RuntimeException("FAIL")
|
case "fail" ⇒ throw new RuntimeException("FAIL")
|
||||||
case _ => param
|
case _ ⇒ param
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def openBreaker: Unit = {
|
def openBreaker: Unit = {
|
||||||
for (i <- 1 to 5)
|
for (i ← 1 to 5)
|
||||||
Await.result(breakers.breaker.withCircuitBreaker(Future(unreliableCall("fail"))) recoverWith {
|
Await.result(breakers.breaker.withCircuitBreaker(Future(unreliableCall("fail"))) recoverWith {
|
||||||
case _ => Promise.successful("OK")
|
case _ ⇒ Promise.successful("OK")
|
||||||
}, 1.second.dilated)
|
}, 1.second.dilated)
|
||||||
}
|
}
|
||||||
|
|
||||||
"A circuit breaker being called by many threads" must {
|
"A circuit breaker being called by many threads" must {
|
||||||
"allow many calls while in closed state with no errors" in {
|
"allow many calls while in closed state with no errors" in {
|
||||||
|
|
||||||
val futures = for (i <- 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {Thread.sleep(10); unreliableCall("succeed")})
|
val futures = for (i ← 1 to 100) yield breakers.breaker.withCircuitBreaker(Future { Thread.sleep(10); unreliableCall("succeed") })
|
||||||
|
|
||||||
val futureList = Future.sequence(futures)
|
val futureList = Future.sequence(futures)
|
||||||
|
|
||||||
val result = Await.result(futureList, 1.second.dilated)
|
val result = Await.result(futureList, 1.second.dilated)
|
||||||
|
|
||||||
result.size must be (100)
|
result.size must be(100)
|
||||||
result.distinct.size must be (1)
|
result.distinct.size must be(1)
|
||||||
result.distinct must contain ("succeed")
|
result.distinct must contain("succeed")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,19 +59,19 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
||||||
|
|
||||||
openBreaker
|
openBreaker
|
||||||
|
|
||||||
val futures = for (i <- 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {
|
val futures = for (i ← 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {
|
||||||
Thread.sleep(10); unreliableCall("success")
|
Thread.sleep(10); unreliableCall("success")
|
||||||
}) recoverWith {
|
}) recoverWith {
|
||||||
case _: CircuitBreakerOpenException => Promise.successful("CBO")
|
case _: CircuitBreakerOpenException ⇒ Promise.successful("CBO")
|
||||||
}
|
}
|
||||||
|
|
||||||
val futureList = Future.sequence(futures)
|
val futureList = Future.sequence(futures)
|
||||||
|
|
||||||
val result = Await.result(futureList, 1.second.dilated)
|
val result = Await.result(futureList, 1.second.dilated)
|
||||||
|
|
||||||
result.size must be (100)
|
result.size must be(100)
|
||||||
result.distinct.size must be (1)
|
result.distinct.size must be(1)
|
||||||
result.distinct must contain ("CBO")
|
result.distinct must contain("CBO")
|
||||||
}
|
}
|
||||||
|
|
||||||
"allow a single call through in half-open state" in {
|
"allow a single call through in half-open state" in {
|
||||||
|
|
@ -79,20 +79,20 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
||||||
|
|
||||||
Await.ready(breakers.halfOpenLatch, 2.seconds.dilated)
|
Await.ready(breakers.halfOpenLatch, 2.seconds.dilated)
|
||||||
|
|
||||||
val futures = for (i <- 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {
|
val futures = for (i ← 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {
|
||||||
Thread.sleep(10); unreliableCall("succeed")
|
Thread.sleep(10); unreliableCall("succeed")
|
||||||
}) recoverWith {
|
}) recoverWith {
|
||||||
case _: CircuitBreakerOpenException => Promise.successful("CBO")
|
case _: CircuitBreakerOpenException ⇒ Promise.successful("CBO")
|
||||||
}
|
}
|
||||||
|
|
||||||
val futureList = Future.sequence(futures)
|
val futureList = Future.sequence(futures)
|
||||||
|
|
||||||
val result = Await.result(futureList, 1.second.dilated)
|
val result = Await.result(futureList, 1.second.dilated)
|
||||||
|
|
||||||
result.size must be (100)
|
result.size must be(100)
|
||||||
result.distinct.size must be (2)
|
result.distinct.size must be(2)
|
||||||
result.distinct must contain ("succeed")
|
result.distinct must contain("succeed")
|
||||||
result.distinct must contain ("CBO")
|
result.distinct must contain("CBO")
|
||||||
}
|
}
|
||||||
|
|
||||||
"recover and reset the breaker after the reset timeout" in {
|
"recover and reset the breaker after the reset timeout" in {
|
||||||
|
|
@ -102,19 +102,19 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
|
||||||
|
|
||||||
Await.ready(breakers.breaker.withCircuitBreaker(Future(unreliableCall("succeed"))), 1.second.dilated)
|
Await.ready(breakers.breaker.withCircuitBreaker(Future(unreliableCall("succeed"))), 1.second.dilated)
|
||||||
|
|
||||||
val futures = for (i <- 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {
|
val futures = for (i ← 1 to 100) yield breakers.breaker.withCircuitBreaker(Future {
|
||||||
Thread.sleep(10); unreliableCall("succeed")
|
Thread.sleep(10); unreliableCall("succeed")
|
||||||
}) recoverWith {
|
}) recoverWith {
|
||||||
case _: CircuitBreakerOpenException => Promise.successful("CBO")
|
case _: CircuitBreakerOpenException ⇒ Promise.successful("CBO")
|
||||||
}
|
}
|
||||||
|
|
||||||
val futureList = Future.sequence(futures)
|
val futureList = Future.sequence(futures)
|
||||||
|
|
||||||
val result = Await.result(futureList, 1.second.dilated)
|
val result = Await.result(futureList, 1.second.dilated)
|
||||||
|
|
||||||
result.size must be (100)
|
result.size must be(100)
|
||||||
result.distinct.size must be (1)
|
result.distinct.size must be(1)
|
||||||
result.distinct must contain ("succeed")
|
result.distinct must contain("succeed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ class CircuitBreaker(scheduler: Scheduler, maxFailures: Int, callTimeout: Durati
|
||||||
catch {
|
catch {
|
||||||
case NonFatal(t) ⇒ Promise.failed(t)(CircuitBreaker.syncExecutionContext)
|
case NonFatal(t) ⇒ Promise.failed(t)(CircuitBreaker.syncExecutionContext)
|
||||||
}
|
}
|
||||||
}),callTimeout)
|
}), callTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import akka.event.Logging
|
||||||
|
|
||||||
//#imports1
|
//#imports1
|
||||||
|
|
||||||
class CircuitBreakerDocSpec { }
|
class CircuitBreakerDocSpec {}
|
||||||
|
|
||||||
//#circuit-breaker-initialization
|
//#circuit-breaker-initialization
|
||||||
class DangerousActor extends Actor {
|
class DangerousActor extends Actor {
|
||||||
|
|
@ -26,18 +26,18 @@ class DangerousActor extends Actor {
|
||||||
|
|
||||||
def notifyMeOnOpen =
|
def notifyMeOnOpen =
|
||||||
log.warning("My CircuitBreaker is now open, and will not close for one minute")
|
log.warning("My CircuitBreaker is now open, and will not close for one minute")
|
||||||
//#circuit-breaker-initialization
|
//#circuit-breaker-initialization
|
||||||
|
|
||||||
//#circuit-breaker-usage
|
//#circuit-breaker-usage
|
||||||
def dangerousCall: String = "This really isn't that dangerous of a call after all"
|
def dangerousCall: String = "This really isn't that dangerous of a call after all"
|
||||||
|
|
||||||
def receive = {
|
def receive = {
|
||||||
case "is my middle name" =>
|
case "is my middle name" ⇒
|
||||||
sender ! breaker.withCircuitBreaker(Future(dangerousCall))
|
sender ! breaker.withCircuitBreaker(Future(dangerousCall))
|
||||||
case "block for me" =>
|
case "block for me" ⇒
|
||||||
sender ! breaker.withSyncCircuitBreaker(dangerousCall)
|
sender ! breaker.withSyncCircuitBreaker(dangerousCall)
|
||||||
}
|
}
|
||||||
//#circuit-breaker-usage
|
//#circuit-breaker-usage
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ class MyMessageQueue(_owner: ActorContext)
|
||||||
val storage = new QueueStorage
|
val storage = new QueueStorage
|
||||||
// A real-world implmentation would use configuration to set the last
|
// A real-world implmentation would use configuration to set the last
|
||||||
// three parameters below
|
// three parameters below
|
||||||
val breaker = CircuitBreaker(_owner.system.scheduler,5,30.seconds,1.minute)
|
val breaker = CircuitBreaker(_owner.system.scheduler, 5, 30.seconds, 1.minute)
|
||||||
|
|
||||||
def enqueue(receiver: ActorRef, envelope: Envelope): Unit = breaker.withSyncCircuitBreaker {
|
def enqueue(receiver: ActorRef, envelope: Envelope): Unit = breaker.withSyncCircuitBreaker {
|
||||||
val data: Array[Byte] = serialize(envelope)
|
val data: Array[Byte] = serialize(envelope)
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,15 @@ akka {
|
||||||
# (I) Maximum total size of all channels, 0 for off
|
# (I) Maximum total size of all channels, 0 for off
|
||||||
max-total-memory-size = 0b
|
max-total-memory-size = 0b
|
||||||
|
|
||||||
|
# (I&O) Sets the high water mark for the in and outbound sockets, set to 0b for platform default
|
||||||
|
write-buffer-high-water-mark = 0b
|
||||||
|
|
||||||
|
# (I&O) Sets the send buffer size of the Sockets, set to 0b for platform default
|
||||||
|
send-buffer-size = 0b
|
||||||
|
|
||||||
|
# (I&O) Sets the receive buffer size of the Sockets, set to 0b for platform default
|
||||||
|
receive-buffer-size = 0b
|
||||||
|
|
||||||
# (O) Time between reconnect attempts for active clients
|
# (O) Time between reconnect attempts for active clients
|
||||||
reconnect-delay = 5s
|
reconnect-delay = 5s
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,12 @@ private[akka] class ActiveRemoteClient private[akka] (
|
||||||
b.setOption("tcpNoDelay", true)
|
b.setOption("tcpNoDelay", true)
|
||||||
b.setOption("keepAlive", true)
|
b.setOption("keepAlive", true)
|
||||||
b.setOption("connectTimeoutMillis", settings.ConnectionTimeout.toMillis)
|
b.setOption("connectTimeoutMillis", settings.ConnectionTimeout.toMillis)
|
||||||
|
if (settings.ReceiveBufferSize.isDefined)
|
||||||
|
b.setOption("receiveBufferSize", settings.ReceiveBufferSize.get)
|
||||||
|
if (settings.SendBufferSize.isDefined)
|
||||||
|
b.setOption("sendBufferSize", settings.SendBufferSize.get)
|
||||||
|
if (settings.WriteBufferHighWaterMark.isDefined)
|
||||||
|
b.setOption("writeBufferHighWaterMark", settings.WriteBufferHighWaterMark.get)
|
||||||
settings.OutboundLocalAddress.foreach(s ⇒ b.setOption("localAddress", new InetSocketAddress(s, 0)))
|
settings.OutboundLocalAddress.foreach(s ⇒ b.setOption("localAddress", new InetSocketAddress(s, 0)))
|
||||||
bootstrap = b
|
bootstrap = b
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,12 @@ private[akka] class NettyRemoteServer(val netty: NettyRemoteTransport) {
|
||||||
b.setOption("tcpNoDelay", true)
|
b.setOption("tcpNoDelay", true)
|
||||||
b.setOption("child.keepAlive", true)
|
b.setOption("child.keepAlive", true)
|
||||||
b.setOption("reuseAddress", true)
|
b.setOption("reuseAddress", true)
|
||||||
|
if (settings.ReceiveBufferSize.isDefined)
|
||||||
|
b.setOption("receiveBufferSize", settings.ReceiveBufferSize.get)
|
||||||
|
if (settings.SendBufferSize.isDefined)
|
||||||
|
b.setOption("sendBufferSize", settings.SendBufferSize.get)
|
||||||
|
if (settings.WriteBufferHighWaterMark.isDefined)
|
||||||
|
b.setOption("writeBufferHighWaterMark", settings.WriteBufferHighWaterMark.get)
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,20 @@ private[akka] class NettySettings(config: Config, val systemName: String) {
|
||||||
val WriteTimeout: Duration = Duration(getMilliseconds("write-timeout"), MILLISECONDS)
|
val WriteTimeout: Duration = Duration(getMilliseconds("write-timeout"), MILLISECONDS)
|
||||||
val AllTimeout: Duration = Duration(getMilliseconds("all-timeout"), MILLISECONDS)
|
val AllTimeout: Duration = Duration(getMilliseconds("all-timeout"), MILLISECONDS)
|
||||||
val ReconnectDelay: Duration = Duration(getMilliseconds("reconnect-delay"), MILLISECONDS)
|
val ReconnectDelay: Duration = Duration(getMilliseconds("reconnect-delay"), MILLISECONDS)
|
||||||
|
|
||||||
val MessageFrameSize: Int = getBytes("message-frame-size").toInt
|
val MessageFrameSize: Int = getBytes("message-frame-size").toInt
|
||||||
|
|
||||||
|
private[this] def optionSize(s: String): Option[Int] = getBytes(s).toInt match {
|
||||||
|
case 0 ⇒ None
|
||||||
|
case x if x < 0 ⇒
|
||||||
|
throw new ConfigurationException("Setting '%s' must be 0 or positive (and fit in an Int)" format s)
|
||||||
|
case other ⇒ Some(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
val WriteBufferHighWaterMark: Option[Int] = optionSize("write-buffer-high-water-mark")
|
||||||
|
val SendBufferSize: Option[Int] = optionSize("send-buffer-size")
|
||||||
|
val ReceiveBufferSize: Option[Int] = optionSize("receive-buffer-size")
|
||||||
|
|
||||||
val Hostname: String = getString("hostname") match {
|
val Hostname: String = getString("hostname") match {
|
||||||
case "" ⇒ InetAddress.getLocalHost.getHostAddress
|
case "" ⇒ InetAddress.getLocalHost.getHostAddress
|
||||||
case value ⇒ value
|
case value ⇒ value
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,9 @@ class RemoteConfigSpec extends AkkaSpec(
|
||||||
WriteTimeout must be(10 seconds)
|
WriteTimeout must be(10 seconds)
|
||||||
AllTimeout must be(0 millis)
|
AllTimeout must be(0 millis)
|
||||||
ReconnectionTimeWindow must be(10 minutes)
|
ReconnectionTimeWindow must be(10 minutes)
|
||||||
|
WriteBufferHighWaterMark must be(None)
|
||||||
|
SendBufferSize must be(None)
|
||||||
|
ReceiveBufferSize must be(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue