- 手艺 tags:
- clojure
- opensource published: true comments: true
Last week, I prototyped an RPC framework, slacker, by clojure and for clojure.
What I did ?
Suppose you have a sets of clojure functions to expose. Define them under a namespace:[cc lang="clojure"]
(ns slapi)
(defn timestamp []
(System/currentTimeMillis))
;; ...more functions
[/cc]
Expose the namespace with slacker server, on port 2104:
[cc lang="clojure"]
(use 'slacker.server)
(start-slacker-server (the-ns 'slapi) 2104)[/cc]
On the client side, we use the `defremote` macro to create a facade for `timestamp` function. This API will keep the client code consistent with local mode.
[cc lang="clojure"]
(use 'slacker.client)
(def sc (slackerc "localhost" 2104))
(defremote sc timestamp)
(timestamp)
[/cc]
Internally, slacker uses aleph for transport and carbonite for serialization. I forked carbonite and made it compatible with clojure 1.2 because the aleph mainline is still running on 1.2.
Going further
High-Order Functions
In clojure, functions are treated as first class value. Within memory, you can pass function as parameter to another function. However, this is not supported by serialization framework. So is it possible to add support for that in future?Lazy sequence as parameter
This is another interesting feature in clojure function call. You can pass a lazy-sequence to clojure function. In RPC, it requires parameters to be evaluated on the server side.[cc lang="clojure"]
(defn get-first [& args] (first args))
(apply get-first (range))
[/cc]
Example copied from StackOverflow
Coordinated states between several remote servers
With RPC, we can update states on several servers. So do we need something like distributed dosync:[cc lang="clojure"]
(defremote a1 update-a1-state)
(defremote a2 update-a2-state)
(dosync-distributed
(update-a1-state some-value)
(update-a2-state some-value))
[/cc]
I'm not sure if this is a valid scenario in real world but I think it's an interesting topic.(distributed STM?)