折腾了一个上午,终于把我的 VPS 上的 Apache 跑着的相关服务,都切换到 Nginx 上了:
1. Blog 用的是 WordPress,原先是用 mod_php 跑着的,现在则换成了 php-fpm
2. Wiki 用的是 Trac,原先是用的 mod_python,现在用 tracd 直接起来,然后 Nginx 转发
3. Git 前端用的是 Gitweb,因为懒得再启一个 spawn-fcgi 了,所以干脆换成 GitPHP,同样通过 php-fpm 的方式跑着
4. Zotero 的 WebDAV 存储,由于好久都不用,直接停了,有时间再看看有没有什么轻便的替代方案吧

PS1:关于 Gentoo 上的 php-fpm 配置,见 http://bugs.gentoo.org/show_bug.cgi?id=208155http://bugs.gentoo.org/show_bug.cgi?id=301279
PS2:关于 Nginx 跑 WordPress 的 Permalink 设置,可以参考 http://blog.sjinks.pro/wordpress-plugins/nginx-compatibility/

Tags: , , , ,

事情的起因是这样子的,小员在写一个测试工具,主要是管理 Xvfb 和 Selenium Server,启动多个 Server 来并行跑多个测试用例,出错的时候截图生成报告。
然后开发人员的测试代码是这么写的:

1
2
def setUP(self):
    self.selenium = selenium(host, port, "*firefox", "http://xxx.yyy.zzz:1234/")

这里的 host 和 port 在测试用例里是写死的,而在这个测试工具中,由于启动的 Selenium Server 的端口是随机绑定的,所以需要自动的把测试用例里的连接修改成对应的参数。
我俩讨论了下,决定用 decorator 来改掉 selenium 的构造函数,然后有了以下关键部分的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def change_selenium_params(host, port, browser='', baseURL=''):
    def inner(func):
        def wrapper(*kargs, **kwargs):
            kargs = list(kargs)
            kargs[1:3] = host, port
            return func(*kargs, **kwargs)
        return wrapper
    return inner
 
@stop_servers
def run(self):
    """
    Run testcases
    """
    self.xvfb.start()
    self.selenium_server = serverctl.SeleniumServer(self.xvfb.display)
    self.selenium_server.start()
 
    for testcase_file in self.testcases_status['waiting']:
        selenium.selenium._init_ = change_selenium_params('localhost', self.selenium_server.port)(selenium.selenium.__init__)
 
        # Make testsuite and run it here
        ......
 
        self.selenium_server.restart()
 
    self.selenium_server.stop()
    self.xvfb.stop()

由于 Selenium 关闭 Firefox 有 Bug,所以不得不每跑一个 testsuite 就重启一次 Selenium Server,这时候发现 testsuite 用的还是第一次传过去的端口。结果看起来奇怪,这个问题还和其它混在一起了,而且这玩意比较难跟踪,调试器也不好用,于是乎,我们写了个简化版的原型来分析,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Selenium:
    def __init__(self, port):
        print 'Port:', port
 
def change_port(port):
    def inner(func):
        def wrapper(*kargs, **kwargs):
            kargs = list(kargs)
            kargs[1] = port
            return func(*kargs, **kwargs)
        return wrapper
    return inner
 
for i in xrange(3):
    Selenium.__init__ = change_port(i)(Selenium.__init__)
    a = Selenium(9)

这时候的输出是:

1
2
3
Port: 0
Port: 0
Port: 0

然后在 decorator 里加了条输出语句:

1
2
3
4
5
6
7
8
9
def change_port(port):
    def inner(func):
        def wrapper(*kargs, **kwargs):
            kargs = list(kargs)
            print 'Change port:', port  # Add a debug output.
            kargs[1] = port
            return func(*kargs, **kwargs)
        return wrapper
    return inner

这时候的输出是:

1
2
3
4
5
6
7
8
9
Change port: 0
Port: 0
Change port: 1
Change port: 0
Port: 0
Change port: 2
Change port: 1
Change port: 0
Port: 0

这下终于知道问题所在了,可怜的 A.__init__ 函数每次执行都多被套一层 decorator,到了最后就变成了:

1
change_port(2)(change_port(1)(change_port(0)(A.__init__)))

嗯,用个临时变量先把初始的 A.__init__ 保存起来就 OK 了,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class A:
    def __init__(self, port):
        print 'Port:', port
 
orig_func = A.__init__
 
def change_port(port):
    def inner(func):
        def wrapper(*kargs, **kwargs):
            kargs = list(kargs)
            print 'Change port:', port  # Add a debug output.
            kargs[1] = port
            return func(*kargs, **kwargs)
        return wrapper
    return inner
 
for i in xrange(3):
    A.__init__ = orig_func
    A.__init__ = change_port(i)(A.__init__)
    a = A(9)

Tags:

发发牢骚…

Essay August 23rd, 2009

有时候真的怀疑本应是明年的本命年提前过了,毕竟这一年下来,真的是没什么顺心的事情。被妹子发卡就不说了,毕竟感情的事不是努力就能成的,也只能无可奈何的等伤口慢慢恢复了…

之后过了段时间,由于一些个人原因,辞职宅宿舍了,结果又遇到搞笑的事情。投了家新加坡的创业公司,一开始觉得他们做的东西蛮有意思的,而且还可以异地办公,这样我就可以迁移杭州了。于是和他们作了个 Skype 的面试,说是接下来安排个小项目来试试看。嗯,过了好几天,没动静,发邮件催了下,说是很抱歉,最近比较忙,所以要我再等几天。在这之后就是漫长的等待,IM 上和他们讨论了几次服务器的性能问题,还帮他们弄优化方案的原型,每次聊完总是说让我等那个测试项目。最近更牛掰了,干脆 IM 和 Email 都不回复了… 我都无语了,哥们,你要是不招直说啊,每次都说再等等啥意思呢,要么像现在这样子干脆不回复也成啊。反正啊,是又被忽悠了,想想自个中途还拒了网易的 offer,真是无愧傻多这称号啊…

然后最近看到谷歌宣布 Android 谷歌拼音输入法发布,支持用户词典同步功能,觉得挺不错的。翻了下 Android 的代码仓库,有 PinyinIME 的源代码,于是开始动手移植到 Mac 上,想着如果我 Windows 下也用谷歌拼音的话,两边的词库能同步,挺方便的。结果把原型搞出来后,非常沮丧的发现:
1. 目前的 Android 仓库上的 PinyinIME 源代码里没有网络词库同步的实现…
2. 就算网络词库同步以后加进去了,但是… Android 版本的词库同步和 PC 版本的是独立的,没法共享…
3. Android 版本的词库格式和 PC 版本的不兼容,工程里生成的那 1M 大小的词库实在是太寒碜了,还没法拷 PC 版的来用…
目前的原型继续完善下去感觉也没有必要了,毕竟一开始就是奔着词库同步的优点才动手的,还是老老实实用付费的 QIM 吧…
顺手放个截图缅怀下这个夭折的原型…
fakegou

也许最近唯一还值得欣慰的就是,笑来兄的《TOEFL核心词汇21天突破》还有坚持每天在背,虽然进度很慢就是了…

Tags: , ,