#2168 - Exposing more Netty options in remtoe config

This commit is contained in:
Viktor Klang 2012-06-01 21:29:47 +02:00
parent 2940740c48
commit 12b9af25cf
9 changed files with 83 additions and 47 deletions

View file

@ -6,7 +6,7 @@ package akka.pattern
import akka.testkit._
import akka.util.duration._
import org.scalatest.BeforeAndAfter
import akka.dispatch.{Promise, Await, Future}
import akka.dispatch.{ Promise, Await, Future }
class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
@ -17,7 +17,7 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
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())
}
@ -28,30 +28,30 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
def unreliableCall(param: String) = {
param match {
case "fail" => throw new RuntimeException("FAIL")
case _ => param
case "fail" throw new RuntimeException("FAIL")
case _ param
}
}
def openBreaker: Unit = {
for (i <- 1 to 5)
for (i 1 to 5)
Await.result(breakers.breaker.withCircuitBreaker(Future(unreliableCall("fail"))) recoverWith {
case _ => Promise.successful("OK")
case _ Promise.successful("OK")
}, 1.second.dilated)
}
"A circuit breaker being called by many threads" must {
"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 result = Await.result(futureList, 1.second.dilated)
result.size must be (100)
result.distinct.size must be (1)
result.distinct must contain ("succeed")
result.size must be(100)
result.distinct.size must be(1)
result.distinct must contain("succeed")
}
@ -59,19 +59,19 @@ class CircuitBreakerMTSpec extends AkkaSpec with BeforeAndAfter {
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")
}) recoverWith {
case _: CircuitBreakerOpenException => Promise.successful("CBO")
case _: CircuitBreakerOpenException Promise.successful("CBO")
}
val futureList = Future.sequence(futures)
val result = Await.result(futureList, 1.second.dilated)
result.size must be (100)
result.distinct.size must be (1)
result.distinct must contain ("CBO")
result.size must be(100)
result.distinct.size must be(1)
result.distinct must contain("CBO")
}
"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)
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")
}) recoverWith {
case _: CircuitBreakerOpenException => Promise.successful("CBO")
case _: CircuitBreakerOpenException Promise.successful("CBO")
}
val futureList = Future.sequence(futures)
val result = Await.result(futureList, 1.second.dilated)
result.size must be (100)
result.distinct.size must be (2)
result.distinct must contain ("succeed")
result.distinct must contain ("CBO")
result.size must be(100)
result.distinct.size must be(2)
result.distinct must contain("succeed")
result.distinct must contain("CBO")
}
"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)
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")
}) recoverWith {
case _: CircuitBreakerOpenException => Promise.successful("CBO")
case _: CircuitBreakerOpenException Promise.successful("CBO")
}
val futureList = Future.sequence(futures)
val result = Await.result(futureList, 1.second.dilated)
result.size must be (100)
result.distinct.size must be (1)
result.distinct must contain ("succeed")
result.size must be(100)
result.distinct.size must be(1)
result.distinct must contain("succeed")
}
}

View file

@ -142,7 +142,7 @@ class CircuitBreaker(scheduler: Scheduler, maxFailures: Int, callTimeout: Durati
catch {
case NonFatal(t) Promise.failed(t)(CircuitBreaker.syncExecutionContext)
}
}),callTimeout)
}), callTimeout)
}
/**

View file

@ -13,7 +13,7 @@ import akka.event.Logging
//#imports1
class CircuitBreakerDocSpec { }
class CircuitBreakerDocSpec {}
//#circuit-breaker-initialization
class DangerousActor extends Actor {
@ -26,18 +26,18 @@ class DangerousActor extends Actor {
def notifyMeOnOpen =
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 receive = {
case "is my middle name" =>
case "is my middle name"
sender ! breaker.withCircuitBreaker(Future(dangerousCall))
case "block for me" =>
case "block for me"
sender ! breaker.withSyncCircuitBreaker(dangerousCall)
}
//#circuit-breaker-usage
//#circuit-breaker-usage
}

View file

@ -69,7 +69,7 @@ class MyMessageQueue(_owner: ActorContext)
val storage = new QueueStorage
// A real-world implmentation would use configuration to set the last
// 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 {
val data: Array[Byte] = serialize(envelope)

View file

@ -133,6 +133,15 @@ akka {
# (I) Maximum total size of all channels, 0 for off
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
reconnect-delay = 5s

View file

@ -147,6 +147,12 @@ private[akka] class ActiveRemoteClient private[akka] (
b.setOption("tcpNoDelay", true)
b.setOption("keepAlive", true)
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)))
bootstrap = b

View file

@ -45,6 +45,12 @@ private[akka] class NettyRemoteServer(val netty: NettyRemoteTransport) {
b.setOption("tcpNoDelay", true)
b.setOption("child.keepAlive", 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
}

View file

@ -37,8 +37,20 @@ private[akka] class NettySettings(config: Config, val systemName: String) {
val WriteTimeout: Duration = Duration(getMilliseconds("write-timeout"), MILLISECONDS)
val AllTimeout: Duration = Duration(getMilliseconds("all-timeout"), MILLISECONDS)
val ReconnectDelay: Duration = Duration(getMilliseconds("reconnect-delay"), MILLISECONDS)
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 {
case "" InetAddress.getLocalHost.getHostAddress
case value value

View file

@ -56,6 +56,9 @@ class RemoteConfigSpec extends AkkaSpec(
WriteTimeout must be(10 seconds)
AllTimeout must be(0 millis)
ReconnectionTimeWindow must be(10 minutes)
WriteBufferHighWaterMark must be(None)
SendBufferSize must be(None)
ReceiveBufferSize must be(None)
}
}