Skip to content
This repository has been archived by the owner on Jan 20, 2025. It is now read-only.

Services

xsc edited this page Apr 24, 2013 · 9 revisions

Implementing a Service

To implement a service you have to first import it using either thrift-clj.core/import-services or thrift-clj.core/import with the :services key. You might have to import the used types, too.

(require '[thrift-clj.core :as thrift])
(thrift/import-services org.example.PersonIndex)

;; or:
(thrift/import 
  (:services org.example.PersonIndex)
  (:types org.example.Person))

Now, let's say the service looks like this:

service PersonIndex {
  bool storePerson(1:i32 id, 2:Person p),
  Person getPerson(1:i32 id)
}

You can now use service, defservice and defservice-fn to create an instance of it.

service

Service takes the service class (or an alias) to implement, a number of options identified by a keyword, as well as a defrecord/deftype-like list of methods, and generates an instance of <Service>$Iface.

Options include:

  • :let: a vector of bindings; actually, service does not benefit from this option since you could as well wrap it in a let block completely - but defservice and defservice-fn probably do.

service is a macro that directly returns a value, not creating any var. So, either use it directly with one of the server generation functions (see below), or store it somewhere.

(let [s (thrift/service PersonIndex
          (storePerson [id {:keys[firstName lastName age]}]
            (println "Storing" (str "[" lastName ", " firstName ", " age "]") "...")
            (boolean (store-in-db id firstName lastName age)))
          (getPerson [id]
            (let [[f l a] (get-from-db id)]
              (Person. f l a))))]
  (thrift/serve-and-block! 
    (thrift/single-threaded-server s PORT)))

As you can see, thrift-clj handles Thrift objects for you, transparently converting them between their original and their Clojure representations. You can thus use things like destructuring, map lookup, etc...

defservice/defservice-fn

These two macros are small helpers to declare service vars and service generation functions.

  • (thrift/defservice id ...) translates to (def id (thrift/service ...)), and
  • (thrift/defservice-fn id [a b c] ...) translates to (defn id [a b c] (thrift/service ...)).

Just one less pair of parentheses.

Running a Server

There are three different server generation functions, each taking a service instance (generated by one of the macros above) as first parameter, followed by a port number and some options like :protocol (see here for possible values), and producing an instance of org.apache.thrift.server.TServer.

Options include:

  • :protocol: the protocol to use for encoding/decoding;
  • :bind: the local address (a string) to bind the server to;
  • :client-timeout: maximum waiting time for responses/requests from a client.

You can create the following servers:

  • single-threaded-server
  • multi-threaded-server
  • nonblocking-server ( Note : This needs a framed or fast-framed client transport which is available since version "0.1.1".)

And these functions will start/stop them for you:

  • serve!: returns a future containing the started server;
  • serve-and-block!: starts the server, blocks indefinitely;
  • stop!: shuts the server down.

Example using serve!, stopping the server after 60s:

(thrift/defservice json-service ...)

(let [srv (thrift/multi-threaded-server json-service 1234 
            :bind "127.0.0.1" 
            :protocol :json)
      f (thrift/serve! srv)]
  (Thread/sleep 60000)
  (thrift/stop! f)
  @f)
Clone this wiki locally