Skip to content

Instantly share code, notes, and snippets.

@leedm777
Created August 1, 2012 23:06
Show Gist options
  • Save leedm777/3231456 to your computer and use it in GitHub Desktop.
Save leedm777/3231456 to your computer and use it in GitHub Desktop.
Snippets for Akka Future's talk
// 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