Skip to content

Instantly share code, notes, and snippets.

@agleyzer
Created October 10, 2013 18:01
Show Gist options
  • Save agleyzer/6922765 to your computer and use it in GitHub Desktop.
Save agleyzer/6922765 to your computer and use it in GitHub Desktop.
NYT Code Weekly Finagle Demo
import com.twitter.conversions.time._
import com.twitter.finagle.Service
import com.twitter.finagle.builder.{ClientBuilder, Server, ServerBuilder}
import com.twitter.finagle.http.{Http, Request, Response, RichHttp}
import com.twitter.finagle.util.DefaultTimer
import com.twitter.finagle.util.DefaultTimer.{twitter => timer}
import com.twitter.util.{Await, Future, Stopwatch}
import java.net.{InetSocketAddress, SocketAddress}
import org.jboss.netty.handler.codec.http.HttpResponseStatus
import scala.util.Random
object demo {
// a Future can hold a result of a future computation
Future {
// call server...
42
}
// constant value
Future.value(42)
// or an error
Future.exception(new RuntimeException("dang!"))
// we can block to get result
Await.result(timer.doLater(1.second)("hello"))
// we can block with timeout
Await.result(timer.doLater(3.seconds)("hello"), 1.second)
// we can add callbacks - on success
timer.doLater(1.second)(42) onSuccess { v =>
println("Got " + v)
}
// and on failure
timer.doLater(1.second)(throw new RuntimeException("boo!")) onFailure { ex =>
println("Got " + ex)
}
// a blocking getter with a stopwatch
def get[T](f: Future[T]): Unit = {
val watch = Stopwatch.start()
f onSuccess { v =>
println("\nSUCCESS: %s in %s\n" format (v, watch()))
} onFailure { ex =>
println("\nFAILURE: %s in %s\n" format (ex, watch()))
}
Await.ready(f)
}
get {
timer.doLater(3.seconds) {
"hey there!"
}
}
// map - converting future results
get {
Future.value("hello") map { s =>
s.toUpperCase
}
}
// flatMap - chaining with other async operations
get {
def getFirstName(): Future[String] = Future {
println("getting first name")
"alex"
}
def getLastName(): Future[String] = Future {
println("getting last name")
"gleyzer"
}
def sayHello(name: String): Future[String] = Future {
println("saying hello to " + name)
"hello " + name
}
getFirstName() flatMap { firstName =>
getLastName() flatMap { lastName =>
sayHello(firstName + " " + lastName)
}
}
}
// flatMap - errors are propagated
get {
def getFirstName(): Future[String] = Future {
println("getting first name")
"alex"
}
def getLastName(): Future[String] = Future {
println("getting last name")
throw new RuntimeException("fail!")
}
def sayHello(name: String): Future[String] = Future {
println("saying hello to " + name)
"hello " + name
}
getFirstName() flatMap { firstName =>
getLastName() flatMap { lastName =>
sayHello(firstName + " " + lastName)
}
}
}
// syntactic sugar - for comprehension
get {
def getFirstName(): Future[String] = Future.value("alex")
def getLastName(): Future[String] = Future.value("gleyzer")
def sayHello(name: String): Future[String] = Future.value("hello " + name)
for {
firstName <- getFirstName()
lastName <- getLastName()
hello <- sayHello(firstName + " " + lastName)
} yield hello
}
// let's create an HTTP server faking some work
val rootService = new Service[Request, Response] {
val rnd = new Random(System.currentTimeMillis)
def apply(request: Request) = {
timer.doLater(rnd.nextInt(3).seconds) {
val r = request.getUri match {
case "/boom" => Response(HttpResponseStatus.INTERNAL_SERVER_ERROR)
case _ => Response(HttpResponseStatus.OK)
}
r.contentString = request.getUri.substring(1).reverse
r
}
}
}
val server = ServerBuilder().
codec(RichHttp[Request](Http())).
bindTo(new InetSocketAddress(0)).
name("HttpServer").
build(rootService)
val boundAddress = server.localAddress
// now a client
val client = ClientBuilder().
codec(RichHttp[Request](Http())).
hosts(boundAddress).
hostConnectionLimit(10).
build()
get(client(Request("/hello")))
get(client(Request("/boom")))
// let's wrap client call in a function
def service(s: String): Future[String] =
client(Request("/" + s)) map (_.contentString)
get(service("hello"))
// Sequential composition
get {
for {
s1 <- service("hello")
s2 <- service("alex")
s3 <- service("gleyzer")
} yield (s1 + " " + s2 + " " + s3)
}
// Parallel composition
get {
Future.collect(Seq(service("hello"), service("alex"), service("gleyzer")))
}
// Select first one
get {
val f = Future.select(Seq(service("hello"), service("alex"), service("gleyzer")))
f map { case (first, rest) => first }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment