Created
January 19, 2011 23:08
-
-
Save nkallen/787081 to your computer and use it in GitHub Desktop.
Some scatter/gather timeout idioms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The following code represents the "best effort" idiom, where N parallel requests are made | |
* and for those that fail to return within a global timeout, we use a default value. | |
* | |
* Below are three implementations of the same idiom. The building blocks are CountDown latches, | |
* which are a kind of barrier, and Timer threads. I'm not sure which is best. | |
*/ | |
"Weaver" should { | |
"weave" in { | |
var timer: JavaTimer = null | |
val requests = Seq(new Promise[Int], new Promise[Int], new Promise[Int]) | |
val defaultValue = 1 | |
doBefore { timer = new JavaTimer } | |
doAfter { timer.stop() } | |
"no timer thread and N latches" in { | |
val limit = 1.second.fromNow | |
requests.head.setValue(10) // this one request returns within time. | |
val sum = requests.foldLeft(0) { (sum, request) => | |
// This handles all exceptions with a default value: | |
val value = request.get((limit - Time.now) min 0.seconds).getOrElse(defaultValue) | |
sum + value | |
} | |
sum mustEqual 12 | |
} | |
"one timer thread and N (implicit) latches" in { | |
val bestEffort = requests map { request => | |
request.within(timer, 1.second) handle { | |
case _: TimeoutException => defaultValue | |
} | |
} | |
requests.head.setValue(10) // this one request returns within time. | |
val sum = bestEffort.foldLeft(0) { (sum, requestOrDefault) => | |
sum + requestOrDefault.get() | |
} | |
sum mustEqual 12 | |
} | |
"uses one timer thread and one latch" in { | |
val latch = new CountDownLatch(requests.size) | |
val bestEffort = requests map { request => | |
val defaultIfTimeout = | |
request.within(timer, 1.second) handle { | |
case _: TimeoutException => defaultValue | |
} | |
defaultIfTimeout respond { _ => | |
latch.countDown() | |
} | |
defaultIfTimeout | |
} | |
requests.head.setValue(10) | |
latch.await() | |
val sum = bestEffort.foldLeft(0) { (sum, requestOrDefault) => | |
sum + requestOrDefault.get() | |
} | |
sum mustEqual 12 | |
} | |
} | |
} | |
/** | |
* The following code represents the "first response wins" idiom. | |
*/ | |
"Weaver" should { | |
val requests = Seq(new Promise[Int], new Promise[Int], new Promise[Int]) | |
"weave some more" in { | |
val result = new Promise[Int] | |
requests foreach { request => | |
request respond { reply => | |
result.updateIfEmpty(reply) | |
} | |
} | |
requests.head.setValue(1) | |
result.get() mustEqual 1 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment