A Clojure wrapper around Twitter's Finagle RPC server/client
Finagle is an asynchronous network stack for building RPC clients/servers. See https://github.com/twitter/finagle. This project aims to simplify some of the code needed to generate and work with these clients and servers.
Finagle server/client interfaces can be generated by running Twitter's Scrooge compiler on Thrift IDL files. The first step is to create a Thrift IDL file describing your service. The following example will create the bare mininum to demonstrate usage of this library. For more information, check out http://thrift.apache.org.
(defproject my-awesome-project "0.1"
...
:java-source-path "src/java"
:plugins [[lein-scrooge "0.1.1"]]
:dependencies [[clj-finagle "0.1.2"]]
:scrooge {
:language "Java"
:finagle true
}
...
)
$ mkdir src/thrift
$ vi src/thrift/example.thrift
namespace java com.example
struct Request {
1: required string foo
}
service Example {
void ping(),
string lookup(Request req)
}
If you used the project settings above, then you should be all set to run the lein-scrooge plugin to generate your java source. See http://github.com/jcrean/lein-scrooge for additional details.
$ lein scrooge
$ lein javac
This will generate source code into src/java (or wherever you've configured scrooge to place generated source) and compile.
You need to define how your RPC server will process requests by defining a processor
(see http://thrift.apache.org/docs/concepts/ for more info).
(ns my-namespace
(:use
clj-finagle.core)
(:import
;; generated service code via example.thift.
;; you'll need to import a couple of classes that were generated by Scrooge.
[com.example Example
Example$FutureIface
Example$FinagledService
Example$FinagledClient]))
;; Define a processor for the Example service.
;; Provides implementations of RPC methods defined in your IDL file (example.thrift)
;; NOTE that finagle processors must return com.twitter.util.Future objects.
(def-processor :example-processor Example
(ping [] (com.twitter.util.Future/Void))
(lookup [^Request req]
(if (= "winterfell" (.getFoo req))
(com.twitter.util.Future/value "winter is coming")
(com.twitter.util.Future/value "seven hells!"))))
(register-rpc :example
{:service "Example"
:processor :example-processor
:name "MyAwesomeService"
:port 8888})
(start-server :example)
This will start a Finagle server that listens on the port specified in your config.
The following examples demonstrate how a client would call the two functions we've defined in our example service. It is assumed that register-rpc
has been called already.
Example of calling ping() function that we defined above:
(call-service
:example
(ping)
(onSuccess [ret] (println "server is alive! return value is nil since function returns void"))
(onFailure [^Throwable t] (println (format "something has gone wrong: %s" t))))
Example of calling lookup() function which accepts a Request
object as a parameter and returns a string:
(call-service
:example
(lookup (Request. "winterfell"))
(onSuccess [^String ret] (println (format "got response: %s" ret)))
(onFailure [^Throwable t] (println (format "something has gone wrong: %s" t))))
Copyright © 2013
Distributed under the Eclipse Public License, the same as Clojure.