Created
August 1, 2012 23:06
-
-
Save leedm777/3231456 to your computer and use it in GitHub Desktop.
Snippets for Akka Future's talk
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
// You've gotta start somewhere | |
import akka.dispatch.Future | |
implicit val system = akka.actor.ActorSystem("MySystem") | |
// lame | |
val WHY_YOU_TAKE_SO_LONG: Seq[Kitten] = | |
grep(theWorld, kittens) | |
// awesome | |
val allKittens: Future[Seq[Kitten]] = | |
Future { grep(theWorld, kittens) } | |
// Register callbacks | |
allKittens onSuccess { case kittens => | |
for (kitty <- kittens) self.pet(kitty) | |
} onFailure { case ex => | |
log.error("No kitties", ex) | |
} | |
// Notice that looks like a try/catch block? | |
// You can just get the value | |
allKittens.value match { | |
case Some(Right(kittens)) => | |
for (kitty <- kittens) self.pet(kitty) | |
case Some(Left(ex)) => | |
log.error("No kitties", ex) | |
case None => | |
log.info("No kitties... yet") | |
} | |
// GIVE ME KITTENS!!! | |
import akka.dispatch.Await | |
import akka.util.duration._ | |
try { | |
val kittens = Await.result(allKittens, 30 second) | |
for (kitty <- kittens) self.pet(kitty) | |
} catch { | |
case ex: Exception => | |
log.error("No kitties", ex) | |
} | |
// Like bow ties, monads are cool | |
class Monad[T] { | |
def map[A](f: T => A): Monad[A] | |
def flatMap[A](f: T => Monad[A]): Monad[A] | |
} | |
// ¿Comprehensions, comprende? | |
for (kittens <- allKittens; kitty <- kittens) { | |
// called later when allKittens resolves | |
self.pet(kitty) | |
} | |
// yet your code can continue on | |
// Once a Future has a value, it's set for life | |
val f10 = Future { 10 } | |
val f20 = f10.map { _ + 10 } | |
assert(10 == Await.result(f10, 1 second)) | |
assert(20 == Await.result(f20, 1 second)) | |
// I'm really too pedantic about having code that compiles | |
trait URL | |
trait Params | |
val rootURL = new URL {} | |
val query = new Params {} | |
// World's worst RESTful client | |
trait Response { | |
// ... | |
def findLink(name: String): URL | |
def find(name: String): Seq[Response] | |
} | |
def get(url: URL): Future[Response] = Future { throw new UnsupportedOperationException() } | |
def post(url: URL, params: Params): | |
Future[Response] = Future { throw new UnsupportedOperationException() } | |
// Seq[Future[T]] => Future[Seq[T]] | |
def getAllDetails(detailRefs: Seq[Response]) = | |
Future.sequence { | |
for (ref <- detailRefs) yield { | |
get(ref.findLink("details")) // Future[T] | |
} // Seq[Future[T]] | |
} // Future[Seq[T]] | |
// Who doesn't love HATEOAS? | |
val allDetails: Future[Seq[Response]] = for { | |
root <- get(rootURL) | |
searchURL = root.findLink("search") | |
results <- post(searchURL, query) | |
detailRefs = results.find("details") | |
details <- getAllDetails(detailRefs) | |
} yield details | |
// It looks sequential, but it's async! | |
// Asynchronous code, circa two weeks ago | |
// How often have you had to deal with this: | |
trait Async { | |
def doIt(whenDone: String => Any) | |
} | |
// Either implementing or using, it can get hairy | |
// Provide implementors a more reasonable API | |
trait FAsync { | |
def doIt(): Future[String] | |
} | |
class WrapFAsync(m: FAsync) extends Async { | |
def doIt(whenDone: String => Any) { | |
m.doIt() onSuccess { case r => | |
whenDone(r) | |
} | |
} | |
} | |
import akka.dispatch.Promise | |
// Provide users something more modern, too | |
class WrapAsync(old: Async) extends FAsync { | |
def doIt = { | |
// Promise is a Future you can fulfill yourself | |
val promise = Promise[String]() | |
old.doIt { result => | |
promise.success(result) | |
} | |
promise | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment