GRPC 在 Rails Spring 中的 after fork 错误

最近在 Rails 项目中使用了 Etcd,在 Rails initializers 中初始化 Etcd client,在生产/测试环境均没有问题,但是发现在开发环境的 rails console 中,后续使用其他 GRPC 请求,在初始化 GRPC Stub 的时候,会出现如下 Exception:

RuntimeError: grpc cannot be used before and after forking
from /Users/larry/.gem/ruby/2.4.2/gems/grpc-1.17.1-universal-darwin/src/ruby/lib/grpc/generic/client_stub.rb:47:in `initialize'

按照错误找了一下,发现这段检查是在 grpc 1.16.0 版本中加入的: src/ruby/spec/channel_spec.rb#L106

再深入看一下源码,Ruby 的 GRPC lib 大部分实现是在 c 的 extension 里。首先这个 Exception 是定义如下:

void grpc_ruby_fork_guard() {
  if (grpc_ruby_forked_after_init()) {
    rb_raise(rb_eRuntimeError, "grpc cannot be used before and after forking");
  }
}

再看一下 grpc_ruby_forked_after_init 的定义:

#if GPR_WINDOWS
static void grpc_ruby_set_init_pid(void) {}
static bool grpc_ruby_forked_after_init(void) { return false; }
#else
static pid_t grpc_init_pid;

static void grpc_ruby_set_init_pid(void) {
  GPR_ASSERT(grpc_init_pid == 0);
  grpc_init_pid = getpid();
}

static bool grpc_ruby_forked_after_init(void) {
  GPR_ASSERT(grpc_init_pid != 0);
  return grpc_init_pid != getpid();
}
#endif

在 Windows 上什么也不做;在非 Windows 上,定义 grpc_init_pid 来保存初始化的 pid,并且定义 grpc_ruby_set_init_pid 方法来设置 grpc_init_pid, 和 grpc_ruby_forked_after_init 来检查当前 pid 是不是初始化时候的 pid。

再回来看报错 src/ruby/lib/grpc/generic/client_stub.rb:47:in 'initialize',找到对应的源码可以看到这是初始化 Stub 的时候创建 GRPC::Core::Channel 的地方,那么找到对应的 c 语言源码,是在 github.com/grpc/grpc/src/ruby/ext/grpc/rb_channel.c 中:

static VALUE grpc_rb_channel_init(int argc, VALUE* argv, VALUE self) {
  /* 此处省略 800 字 */

  grpc_ruby_once_init();
  grpc_ruby_fork_guard();

  /* 此处省略 800 字 */
}

我们可以看到在初始化 GRPC::Core::Channel 的时候,前后调用了 grpc_ruby_once_initgrpc_ruby_fork_guard,稍微再跟一下就可以发现 grpc_ruby_once_init 中调用了 grpc_ruby_set_init_pid

到此其实就很清楚了,理一下思路,调用 GRPC::Core::Channel.new 会先调用 grpc_ruby_once_init,如果是首次使用 GRPC,那么会记录下当前进程的 pid;下次再调用 GRPC::Core::Channel.new 的时候,grpc_ruby_fork_guard 会检查当前进程 pid 是否是第一次记录下来的 pid,如果不是,那么会返回开头的错误。

到这里,熟悉 Rails 的同学应该已经明白为什么在 development 环境会有这个问题了吧。由于 Rails 加入了 Spring 的支持,在开发环境启动 Rails 的时候,initializers 被调用 (也就是 Rails Application 被 initialize) 的进程,并不是后续代码执行的进程。

那需要怎么解决呢? Spring 提供了一个 hook:

Spring.after_fork do
  # run arbitrary code
end

可以注册一个 block,这个 block 中的代码将会在 Spring fork 出来之后的进程中执行,所以我们只需要在这个 block 中初始化 Etcd 的 client,就不会碰到再之后使用 GRPC 不在同一个进程的问题了。

golang/dep 如何使用私有 gitlab repo

在简书现在的 golang 项目里面我们使用 dep,毕竟在现在不算很完善的 golang 依赖工具链体系里面,这个项目挺不错的,同时也是官方认可的。

dep is the official experiment, but not yet the official tool. — 摘自 golang/dep 的 Readme

不过最近倒是碰到一个问题,简书内部有一个通用的事件发送 SDK 会发送各种事件到我们的 Kafka。那现在既然有了 golang 的项目,那我们就需要有 Golang 的 SDK。完成这个 SDK 是一件很顺利的事情,但是在将我们自己写的 SDK 引入我们的项目的时候却出现了问题。

因为 SDK 是 host 在我们自己内部的 gitlab repo 上的,所以我理所应当的加入了如下依赖:

[[constraint]]
  branch = "master"
  name = "git.jianshu.io/Qian/go"

但不同于使用 Github 上的开源项目的是,我们自己的 internal gitlab 并不提供 https 的公开使用接口,一切都要走 ssh,然而 dep 并没有为此做好准备。在 Github 上有一个讨论这个问题的 Open Issue: Support for private repositories e.g. Github Enterprisedep/FAQ.md 中也有关于如何使用 API Token 来访问 Github Private Repo 的办法: How do I get dep to consume private git repos using a GitHub Token? 但是用在这里并不适合。

最终还是找到了修改 git 配置的一个办法,修改 ~/.gitconfig 加入如下配置,让 git 在访问 https://git.jianshu.io 的时候自动转为使用 ssh 来访问:

[url "git@git.jianshu.io:"]
	insteadOf = https://git.jianshu.io/

修了一个发生在 Safari 4.1.3 的 Bug

前两天有个用户报告说他在简书无法写作了,就联系上了他帮他检查。他的问题非常奇怪,几乎没有发现有其他人有同样的问题,同时他也在用 Safari 4.1.3,在 Mac OSX Tiger 上,我也找不到相应的测试机来重现。联系上他之后,我发现他算是简书的一个重度作者,已经在简书创作了 10 万字,所以我很想帮他解决这个问题。

先简单说一下这个问题的背景,简书程序的写作部分是一个 Javascript 的 Single Page Application。为了保证用户如果开了两个编辑界面的情况下,不会互相覆盖内容;简书每次请求写作编辑器页面的时候,都会从服务端生成一个版本号给到前端的写作编辑器,保证只让拥有最新版本号的编辑器保存文章内容到服务端。

那么在这个用户浏览器里的问题是,每次打开写作界面,当整个 JS Application 初始化完成后会多发一个 GET Request 到写作编辑器的页面 url,这样话就导致了服务端的版本号更新,但是客户端 JS Application 里没有。所以在他的浏览器里,JS App 里的版本号永远旧于服务端的,以致于他永远也无法正常使用我们的编辑器。

其实发现这个问题不算困难,让我纳闷儿的是,我们的这个 JS App 在所有的我试过的浏览器里都跑的很正常,再请求一次导致版本号错误的问题是很明显的,如果有这样的问题我们一定会很快就发现。

在检查过程的中,我经常很自然的冒出想法觉得是用户的浏览器太旧了,不应该管这个 bug(因为 Safari 4.1.3 仅占我们 Safari 用户的 0.1%),应该让用户升级浏览器(用户很不情愿升级或者下载别的浏览器)。不过每每想到这个用户已经在简书写了这么多字,同时再加上奇怪的问题勾引起来的好奇心(在其他浏览器里都好好的,而且十几天前用户用的也好好的),我就还是硬着头皮继续查错。

整个排错的过程很重复枯燥,没有赘述的必要,我就直接进入揭秘环节吧。下面就是有问题的那行代码:

<img src="" class="imagebubble-image" />

这是一个非常普通的img标签,它会显示一个您当前发布文章的长微博缩略图,由于都是动态 JS 来控制的,所以这里的 src 是根据动态获取了之后类似这样 $el.attr('src', url) 填进去的。

在绝大部分浏览器上这都不会出什么岔子,但是在 Safari 4.1.3 上,有了这个空的 src="",浏览器就会多发一次 GET 请求给当前的 url(这个其实是我根据这次问题的情况做出的猜测,由于没有测试机,没有办法做更多的测试来验证。)。我把这个属性去掉,变成 <img class="imagebubble-image" /> 这个用户的问题就解决了,不会出现请求两次 /writer 导致编辑器版本号永远无法匹配的情况了。

苹果天才吧维修记(续)

相信看过我前一篇博客《苹果天才吧维修记》的朋友,都知道我在 2013.12.06 将我的一台 Macbook Pro 送进上海浦东国金中心 Apple Store 天才吧进行维修。

当时天才吧上确定了三个建议维修的要点,都在给我的回单上写很清楚:

在 2013.12.15 日晚上我接到电话说我电脑修好了,叫我去取,我还挺开心的。

第二天礼拜一,我就提前下班去苹果店拿货。天才吧等待拿货的人也不多,我前面大概有两位,但是符合预期的是我还是等了半个小时,一位天才才把我的电脑从里面拿出来给我检查。

因为后面订了饭店要跟老婆去吃饭,本来我其实是挺放心的,没准备检查,准备拿了就走的,天才说了三次「先生请检查一下您的电脑」。我想那就检查一下吧,按了一下开机,然后开始前看后看。很容易就发现了回车键没换,等到开机了又发现系统也没有重装,我当时就已经出离愤怒了。由于后面还有事情,我就赶紧催促他们收进去再做,做好再给我打电话,就算了。

等到了第二天,也就是昨天下午的时候我接到一个苹果店打来的电话,一个天才说为了要删除我电脑上之前安装的 Bootcamp 需要我的用户密码,我就给他了。要知道电话里要说清楚那么几个字母费了好大功夫,电话那头他貌似是抄下来了就准备挂电话。我想费了那么大劲终于记下来的密码还是先试一下吧,于是就催促他不要挂电话当场试验一下,没想等他电话那边打开我的电脑,他说「哦,原来已经都做好了,那不用密码了」。

就在这个时候,电话那头突然就换了一个人跟我通话,直接通知我今天去拿机器。我十分莫名其妙,就问他所有的维修都做好了么,按键什么的。他说,没有按键啊,就是换主板,我这里看不到需要维修按键啊。

接到如此莫名其妙的电话,加上昨天白跑了一趟,我真是气不打一处来。

( 此处省略一万字… )

在 escalation 到和 Genius Bar 经理通话之后,天才总管俞经理表示无论是什么问题,在苹果都是没有责任人的,一切责任不在维修工程师,不在电话通知的员工,也不在他,而在苹果,在零售店,因为 They are a team! 所以他敦促我,你有气,就还是到店解决这个问题吧,但是他幸灾乐祸的表示他5点就下班了。

我说不行,我6点20才能到。他大包大揽的说,「好,那我叫我们零售店经理某D接待你,不但你6点20来一定能见到他人,我担保让他在门口恭候你」(我反复询问,他确认意思就是在门口等我,并且这是一他承诺的,一定会做到)。我6点20到达国金 AppleStore, 可是哪里有零售店经理恭候?等进去找到他,又是把我推给另外一个经理某K来处理。

然后就又是各种已经听的耳朵出茧子的说辞,无外乎是客户太过计较: 「噢,可能是我们的工作上的疏忽。」 「也许是电话里沟通的误会。」 「咱们都是来解决问题的,既然您电脑现在已经修好了,其他的就不要追究了吧。」

( 此处再次省略一万字 )

经过艰苦卓绝的斗争,两位经理终于承认在这次服务处理中苹果有过错,责任在他们,作为补偿,他们提出给我报销礼拜一白跑一趟的车费和赠送我一个 AppleCare。

最后总结一下,写以前篇的时候,我的槽点还大多在预约环节,当时我觉得只要东西送进去了,苹果的维修是靠谱的。但是这次的经历真是的让我非常失望,苹果天才吧每次维修检查的时候,天才们在那里非常耗时的狂敲 iPad 打字,写了那么冗长的维修建议,最后3项只维修了1项;从头至尾打电话来的人都不了解情况,每一个都是先说了不对的事情被我反问之后再「对不起,我不是负责的那个人,我不太熟悉情况,请给我十分钟我了解一下情况」。还有就是无可奈何的官腔和废话。

真是一次失败的维修。如果他们持续这么烂,强烈支持大家都去要 AppleCare 。

苹果天才吧维修记

想说在前面的是我并不是一个果粉,在感情上对苹果没有任何特殊想法,但是我一直觉得苹果的东西做的的确是很好,近年来一直都在用苹果的各种设备。但是就在今年,两次有幸需要进 Apple Store 到高大上的 Genius Bar 保修,但整个过程让我非常难受。让我觉得自从对服务有认知以来,这是我享受到最差的服务。我在银行排队和去医院看病也没有觉得这么痛苦,而且至少到了之后取号排队,虽然队伍可能很长,但一切是可预测的,你知道如果你越早去,那么你会越早得到服务。而去苹果天才吧,这是不可知的,它必须提前预约,但普通人是预约不到的,所有你能做的也就是去了等,但是就算去的早也不一定能被服务到。另外下面提到的见闻都发生在上海。

1. iPad / iPhone 是不可能预约到的

苹果 iPhone 维修可以当天取机的体验我觉得是非常不错的,但是预约体验绝对可以让你呕血三升,首先 iPhone/iPad 的预约是不可能预约到的。如果你的确在苹果官网经历了艰难险阻最终终于抵达了预约页面,绝大多数情况来讲,你会看到如下画面:

亦或者你会看到网站说他们出现了某描述为「error processing」的错误(今天没试出来所以没有截图,但我相信预约过的朋友肯定都见过),甚至不是一个 500 页面。这两种死法占到了大概十成。

其实早在今年上半年,苹果会专门为临时到店客户预留预约名额,所以那时候如果你起个大早,早早去排队预约,还是有可能预约到的。现在苹果已经取消了这个规则,并且改成只能预约当天维修。不过这也不能成为我们不可能预约到原因,而真实的原因是因为在我们大天朝,这事儿已经有人帮你做掉了:

我在 Apple Store 询问苹果工作人员,说有那么多黄牛把预约都抢掉了卖钱,难道你们不知道么?他们回复说:「这是人家的正当工商行为,如果您有意见请找政府相关部门处理。」

无话可说。

2. 不找黄牛交钱预约你就别想修了

如果你预约不到,就只能直接上门。对于 Mac 用户,这招还是有用的,如果你早上10点就上门,也许在那里等个一个来小时就能有空服务你了,但是 iPhone/iPad 就别想了。我去修MBP的等待的时候和同在等待的旁边一位先生聊天,他说他来修 iPhone, 网上是死活预约不到的,直接上门来了三次都是彻底没机会,现在苹果店的人在帮他联系转到授权维修点去维修,但是这样可能就会需要支付费用,同时也未必可以当天取机了。

我朋友上个礼拜去修 iPad Mini,实在无奈,只能付钱找黄牛了。

3. 预约到了你也要等

苹果的预约让我感到非常不爽的一点是,如果你预约到了,按时来了,还是要等,我今年修了一次 iPhone5,一次 Macbook Pro 每次准时按照预约时间提前5分钟到了天才吧,最后还是多等了半个小时才轮到我维修,这还叫什么预约?

4. 苹果工作人员也不知道该怎么预约

我上个周五去修 Macbook Pro,我知道需要提前预约而且只能预约当天,于是周四半夜就开始刷预约(因为我也不知道什么时候可以开始预约,就半夜开刷),11点58、59刷了两三次,12点过一点又刷了3、4次,全部结果都是错误页面(就是前面提到的 Error Processing),早上9点起床再试,还是错误页面,就只能直接出门跑到苹果店碰运气。

我在苹果店问工作人员 我:「你们到底是怎么预约的?」 果:「请到我们官网预约。」 我:「你们预约什么时候开放呢?」 果:「我们也不知道什么时候开放,请关注我们的官网预约页面。」

服了!

5. 不守时

上周五 2013.12.06 我把我的 MBP 送进天才吧,苹果承诺3天内维修结束会电话联系我去取,直到今天 2013.12.13 没有接到他们的电话。

6. 我猜苹果官网就是在阻止你预约天才吧维修

在苹果中国官网,以你要维修 Macbook Pro 为例,你需要经历点击如下:

「技术支持」 -> 「Mac」-> 「MacBook Pro」-> 「联系支持」-> 「前往 Apple Store 零售店」 -> 「预约服务」-> 「选择你要去哪家 Apple Store」-> 「点击『天才吧预约』」-> 「登录」-> 「再次选择设备 Mac」-> 「选择可用的预约时间」

作为用户体验之王的苹果,需要这样才能找到预约维修的入口,我不得不猜测他是想尽量让用户不要随便有啥事就去预约天才吧,能在网站上看文档解决的就自己解决了吧。当然作为一个企业这也很正常,这点倒是无可厚非。

炒与被炒

译自 Vibhu Norby 的博文 Firing and being fired

我始终记得,我在毕业后的第一份工作中被辞退时的每一个细节。我的经理把我和我们的工程总监带到一个会议室,然后说道:“我们给你带来了一些坏消息,我们不得不让你离开了。其实从最开始,你和公司的文化就不是最契合。我们让你离开并不是因为你不是一个好程序员,只是这里并不适合你。我很抱歉。”

听完这段话,那些刚毕业时害怕失败和无法在硅谷成为一名够格的软件工程师的恐惧感在不到三十秒内凶猛袭来;还有我过去七个月内的工作、没有做完的项目、已经建立了关系的用户、同事之间的友谊 —- 似乎这一切都虚度了。

我没有被允许再回到我的办公室,在被护送出大楼的一路上我都在和泪水做着斗争。我在停车场呆坐了许久,考虑着是不是该到别的地方去,去做一些更容易的工作,或者找一家更大的公司也许压力会更小一点。

我始终记得,那天晚上我修改着我的简历,思索着要是那些有可能聘用我的公司发现我之前被辞退过,那我找工作的希望就算玩完了。如同所有处于我当时境地的人一样,我在心里决定,一旦他们问我,为什么我在上一家公司只做了七个月?我就说是我提出的辞职,或者可能可以说有人在挖我,也许也可以更模糊的说,“我就是离开了”。

两天后,我加入了一个我关注了很久的新公司,和三位十分杰出的人在一个车库中一起工作,解决我认为非常值得解决的问题。在这里,我得到了我需要的编程方面的指导和工具,还有让我在工作中日益精进的鼓励。我的经理们,给予我自由让我拥有创新的空间,也限制我让我保持在通往成功的轨道上。最终我们的公司被收购了,这样看起来,我在第一份工作中被炒成为至今为止发生在我身上最好的事情。

在我真正需要亲自辞退员工之前,我就已经明白,在工作中取得了多大的成就其实就是你是否正在正确的轨道上前进的明确指示。人们无法在工作中取得长期的成功,是因为他们实在太擅长他们的工作了,以至于其他事情都不值一提。而其实只要在对的公司工作,遇到对的管理者,或者热爱自己做的事情,无论起点是高是低,人们最终终归是会成功的。无论在什么方面的成功,都会滋润自身,并持续孕育出成功的果实。

我给被我辞退的工程师说的话和前文提到的一样。尽管当年我感觉我什么也没有做错,但其实我深深的明白,当年炒了我的经理告诉我的话都是真的。在我第一份工作中,我的工作是开发一个基于 ASP.NET 的站点,但其实我很想做一些和开源语言、开源框架相关的工作。在我的第一份工作中,我完成了很多死板的任务,但其实很多我自己的想法最终都没法付诸实践。在我的第一份工作中,我为一个游戏公司工作,但其实那个时候我真正感兴趣的是交流工具。回想往事,我自己没有辞职的唯一原因是当时我没有想要自己掌握自己未来的意识和勇气。所以我的工作绩效帮我说出了我的真正想法。

很多软件团队规模都很小,特别是初创企业。在这样一个小团队里是不像大公司那样有“藏身之处”的,所以预期每个新员工都能很好的融入团队是一种疯狂和不现实的想法。员工对公司的目标和产品缺乏热情会在各个方面表现出来,就算他们仅仅是无法很好的用语言表达公司的目标和产品。当你在一个并不适应的工作岗位上工作的时候,你会慢慢的开始觉得“没人听我说话”,或者你会发现你的经理好像并不满意你的工作或是工作态度。有时候经理在你身边好像变的很怪。有时候经理会要求你改正一下你的工作态度,你确实改正了之后呢他又好像不关心也没有发现。事实上,你感觉到的上级故意不聆听你的诉求、不满意你的工作或是表现的很奇怪,这些感觉都是虚幻的。我认为这是你的意识在给你发出信号,为了你日后的发展和幸福在帮你解读当前的状况:你在其他地方会干的更好。而且的确,你迟早会换地方的。

我们曾经炒掉了大约半打员工,也留下了半打员工。每一个我们炒掉的员工,都去做他们有更大热情、更加擅长亦或是他们更开心的工作了。当你辞退无法融入团队的员工的时候,留下的团队成员会有更强的凝聚力和自我认同感,这对整个团队而言获益匪浅。作为被炒也炒过别人的人,我觉得小公司现在炒人炒的不够多,初创团队的员工工作也换的不够勤。任何程度的面试都没有办法真正考察,即将加入公司的员工内心深处对于公司目标的热情,也无法评估他们的实际工作技能,在这两方面做假都太简单了。

回头来看,我希望我的第一家公司在一察觉到我无法融入团队的时候就把我炒掉,而不是让我又做了几个月。如果员工和企业文化无法契合,在前两个月,有时候最初两个礼拜,甚至可能在入职的第一天就会显现出来。面对炒掉一个员工可以会拖上几个月甚至几年,做出决定让这位错误的员工留下继续工作很容易,然而,早点分手对于公司和员工来说都是更好的选择。

MALESKINE - the mood of writing.

MALESKINE is an online notebook project my team currently working on. We focus on making an application which concentrates on writing. We are about to open the application to public soon, and now we take “Notify me” registrations.

We like to hear as more comments as possible, you could comment here, or via twitter: @larryzhao, @maleskine, here’s an introduction:

Simple is nice.

We provide only the basic necessary features of a notebook instead of making you confused with the menu items and toolbars with functionalities which might never be used.

Writing mode, Writing mood

With the redundancies unloaded, we find out a simple & clean writing area without any interference always brings us the mood of writing.

Markdown supported

MALESKINE supports writing in markdown, we also provide a preview mode for it.

Note on upgrading to Mongoid 3

We’ve been using Mongoid 2.4 for one of our projects for quite some times and it has also gone production in a small group for like two month. It works well and I really love this ODM. Thanks to Durran.

Mongoid 3 has been out for like months. Although I have been wanting to try it out, especially when I looked at all the people discussing about it in the Email group, I didn’t find any time to do the upgrade in the last two months. Just yesterday I upgraded to Mongoid 3, and I think the following things are worth noting down.

That’s all I’ve done in my upgrade to Mongoid 3. It’s not all you might run into when you upgrade, so definitely remember to check out this one: Mongoid Upgrade

Bundler::GemNotFound deploying with capistrano and rvm to a jruby enviroment

Recently I get this problem when deploying my project with capistrano to a jruby envrioment.

It raises the error Bundler::GemNotFound when it comes to the task deploy:assets:precompile

* executing `deploy:assets:precompile'
  * executing "cd /opt/app/deploy/entercamp/releases/20120627163015 && /usr/local/rvm/rubies/jruby-1.6.7/bin/jruby --1.9 -S bundle exec rake RAILS_ENV=staging RAILS_GROUPS=assets assets:precompile"
    servers: ["chicago"]
    [chicago] executing command
 ** [out :: chicago] Bundler::GemNotFound: Could not find rake-0.9.2.2 in any of the sources
 ** [out :: chicago]
 ** [out :: chicago] materialize at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/spec_set.rb:90
 ** [out :: chicago]
 ** [out :: chicago] map! at org/jruby/RubyArray.java:2371
 ** [out :: chicago]
 ** [out :: chicago] materialize at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/spec_set.rb:83
 ** [out :: chicago]
 ** [out :: chicago] specs at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/definition.rb:127
 ** [out :: chicago]
 ** [out :: chicago] specs_for at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/definition.rb:172
 ** [out :: chicago]
 ** [out :: chicago] requested_specs at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/definition.rb:161
 ** [out :: chicago]
 ** [out :: chicago] requested_specs at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/environment.rb:23
 ** [out :: chicago]
 ** [out :: chicago] setup at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler/runtime.rb:11
 ** [out :: chicago]
 ** [out :: chicago] setup at /usr/local/rvm/gems/jruby-1.6.7@global/gems/bundler-1.1.4/lib/bundler.rb:107
 ** [out :: chicago]
 ** [out :: chicago] (root) at /usr/local/rvm/gems/jruby-1.6
 ** [out :: chicago] .7@global/gems/bundler-1.1.4/lib/bundler/setup.rb:17
 ** [out :: chicago]
    command finished in 15575ms

But actually the gem is there, correctly installed and if you go to the server and run the command manually you will find it’s actually working.

This is a annoy problem. Yes, I could choose to run the assests:precompile and other stuff on manually on the server. But it would break the automation of capistrano and also would give downtime to the application so I decided to figure this out yesterday.

After a few experiments and with the help of Michal from rvm-capistrano project, it turns out that it’s because my jruby on server was compiled in 1.8 mode, and my project is running on 1.9. So when running the command, it is told to switch to 1.9 using --1.9 argument. And it could not find those gems.

The Solution I need to fix it with reinstalling my jruby on the server with 1.9 as default use the command: rvm install jruby-1.6.7.2 --1.9 or if you already installed, you could use rvm reinstall jruby-1.6.7.2 --1.9

You could find the whole story at: rvm-capistrano-issue-20 and I also filed an issue to jruby team: jruby-issue-219

Hope it helps.

My Meals

These pictures were taken like a month ago. They were my breakfast, lunch and supper.