Clojure RPC, prototyping and early thoughts

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:

(ns slapi)
(defn timestamp []
  (System/currentTimeMillis))

;; ...more functions

Expose the namespace with slacker server, on port 2104:

(use 'slacker.server)
(start-slacker-server (the-ns 'slapi) 2104)

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.

(use 'slacker.client)
(def sc (slackerc "localhost" 2104))
(defremote sc timestamp)
(timestamp)

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.

(defn get-first [& args] (first args))
(apply get-first (range))

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:

(defremote a1 update-a1-state)
(defremote a2 update-a2-state)
(dosync-distributed
  (update-a1-state some-value)
  (update-a2-state some-value))

I’m not sure if this is a valid scenario in real world but I think it’s an interesting topic.(distributed STM?)

Conclusion

RPC is the first step to distributed clojure world. I will keep you updated with my prototype.

Spark in common lisp

还是关于spark的,一石激起千层浪,每个人心中都有一个spark。其实spark脚本刚出来的时候问题很多,但是就是因为产生了共鸣,众人拾柴pull request多。像redis的作者antirez也忍不住自己用c写了一个aspark

说完了别人的,那么来看看我的:clspark,common-lisp的spark。原本是打算用clojure写,但是想到jvm的启动速度,把这个机会留给我的第一个common lisp程序吧。

其实很简单。

common lisp的核心库里没有split,所以这里从cl-cookbook拷贝了一个split的实现,坦白说我还看不太懂这个loop的写法。loop是common lisp中最尴尬的form,因为他的形式太多。这点在clojure中是不存在的。比较一下就能发现,在语言层面,clojure是相对现代得多的lisp方言。

My response to Spark: Visualize your mercurial commit history from commandline

标题长了些。还是用母语吧。

昨天HackerNews上一个小脚本轰动了,所谓山不在高程序不在小。为了响应这个小脚本,我写了一个更加简单的Mercurial(hg)扩展,帮助你输出hg仓库的提交历史。这个feature和github的直方图有点像,在我看来github的直方图是他们最重要的feature之一,它鞭策着你不断地commit。

hg summary

安装:将这个脚本放在任意一处,在你的hgrc中添加:

[extensions]
summary = /path/to/your/script

由于很简单,就不按照mercurial的规范发布了。

再见2011赛季

虽然还有两个月才能结束这个2011年,但是舜天队的赛季已经结束了。经过大半年的鏖战,大起大落之后,最终球队取得了史无前例的第四名,这让我们看了十多年次级联赛的球迷一时间几乎无法接受。今年赶在联赛开始前我换工作回到南京,去主场的机会也比以前上学或是在外地时多了很多,最终今年一共看了6个主场,是看球16年以来最多的一年。当然不出意外明年还要刷新这个纪录!

周三下午请假去球场目送了一下球队。距离明年开赛还有5个月,有一些球员可能转会,有的退役,所以每到最后一轮都是伤离别的时候。只是往年,这个时候都是夕阳西下,三三两两的观众看完无关紧要的比赛鸟兽散去;而今年的最后一轮,我们还为了理论上的一个亚冠机会争取。

2009年加入球队,2011年学习回来后,杨晨是舜天队的领队兼助理教练。在比赛开始前,作为助理教练要带领队员作热身活动。
resized-DSC_0017

队员训练。
resized-DSC_0011
前面两位是去年从降级的长沙金德转投而来的刘建业和任航,刘建业现在也是队里唯一的国脚。两人转会过来以后一直是球队的主力。刘建业负责中场的拦截防守;任航是边后卫,可以胜任左右两边,攻防俱佳。
跟在后面的时候杜文辉和李炽。杜文辉上赛季结束后被国安队清洗,自由转会来到舜天本来希望通过更多的出场机会能获得国家队的席位,结果不料第四轮就重伤缺席了后面的比赛。复出后球队已经更换了教练,不过杜文辉还是舜天队里技术顶尖的球员,经历了一番周折到了赛季末他还是占据了主力的位置。后面李炽是队龄最大的队员之一,2005年从广东来到江苏,伴随球队度过了最艰难的05、06、07年。升级之后,李炽一直在主力和替补之间徘徊,不过最后总能通过努力获得首发的机会。今年李炽合同到期,据说一条微博还让很多球迷以为下赛季他会回到广东,为此,有了这么一条横幅:
resized-DSC_0057

resized-DSC_0035
中间的9号陆博飞是球队的队长,在球场上的角色有点类似皮尔洛。今年陆队已经32岁了,不过据他昨天在广播里说他的状态还可以再踢两年。20号孙可是队里唯一一个能打上主力的由舜天梯队培养出来的队员,今年孙可也经历了最重要的一个赛季,基本上完成了从替补到主力的转换,在比赛中的作用也越来越重要。

罗马尼亚人达纳拉赫,这位仁兄上半赛季经历了漫长的进球荒,如果不是在场上特别积极,恐怕早就收拾东西走人了。好在从对陕西开和之后,状态越来越好,最终打进13球,在射手榜上排到了第三。
resized-DSC_0002

达纳拉赫的诡异爆发得益于身边空降了一名优秀的同伴,塞尔维亚红星队的耶夫迪奇夏季转会来到球队,是球队历史上身价最高的球员(140万美元)。身价在总体上当然还是和能力成正比的,耶夫迪奇半个赛季就打进11个球,是球队在场上最重要的球员。
resized-DSC_0005

后防线上,两个外援塔基耶夫(左)和埃雷尔森(右)。前者是乌兹别克国脚,他的哥哥和弟弟都曾经在天津泰达踢球。后者是球队的老面孔,埃雷尔森从09年就加入球队,一直是后防线上的定海神针,今年也是联赛中的最佳后卫。
resized-DSC_0097

守门员邓小飞也是09年加入球队,前半赛季一直是替补,后来成为主力之后发挥一直很出色,也是球队后半赛季辉煌的功臣。
resized-DSC_0013

resized-DSC_0050
替补席上的秘鲁外援略显落寞,因为在球队没有位置明年他将是唯一一名离队的外援,所以也有球迷专门给他感谢
resized-DSC_0054

resized-DSC_0066
resized-DSC_0071
resized-DSC_0067
resized-DSC_0086
resized-DSC_0099
resized-DSC_0079
比赛最终没有什么悬念地结束,虽然球队没有获得亚冠的名额,不过今年的成绩已经是18年历史上最佳排名。
resized-DSC_0105
球迷聚在场外放完烟火,约定明年再战!
resized-DSC_0127

lein-control 0.2.1 is out

I have updated the leiningen plugin for clojure-control 0.2.1. There is no new feature for it as a plugin. But some new features from upstream are supported and should be highlighted:

SSH command DSL

This feature is committed by me and first announced in clojure-control 0.2.1. With this DSL, you can write your SSH command with some predefined macros which is more readable and enjoyable.

For example, an ssh task can be defined as:

   (deftask :restart-server "restart your jetty server"
          []
          (ssh (cd "/opt/jetty/bin"
                 (run "./jetty.sh restart"))))

which equals to :

   (deftask :restart-server "restart your jetty server"
          []
          (ssh "cd /opt/jetty/bin; ./jetty/sh restart"))

For full document of this DSL, please check the README.

Improved syntax for defcluster

ssh/scp/rsync options in defcluster could be written as a vector:

(defcluster :mycluster
  :ssh-options "-p 44"
  :scp-options "-v"
  :rsync-options ["-arz" "--delete"]
  :clients [
    { :host "c.domain.com" :user "clogin" :ssh-options "-v -p 43"}
  ]
  :user "login"
  :addresses ["a.domain.com" "b.domain.com"])

(code quote from official announcement)

Parallel support

Tasks could be executed in parallel if you add option

:parallel true

on defcluster.

Finally, to use this plugin, add dev-dependency to your project.clj:

        :dev-dependencies [[lein-control "0.2.1"]]

More detailed instructions could be found here.

BTW, this is the last release of lein-control as a standalone artifact. I will be working on merging lein-control into clojure-control. Soon you will have a few flexible ways to use clojure-control.