Spawn a process from a build that lives longer than the build itself in Hudson(Jenkins)
在做持续集成的时候,可能会有这样的需求:
- 在Build过程中,需要启动一个服务器,用来监听服务请求等等
这样的情况,通常build进程本身会启动服务器,然后服务器就一致处于监听状态。
这样就带来了一个问题:由于服务器一直处在监听状态,因此,build进程一直无法结束,就导致了build就被hold住了,永远结束不了。
举个例子:
假设Build过程中需要调用一个ant任务,该任务就负责启动一个jetty服务器,然后一直监听着:
ant runserver
这个时候就会把build过程hold住了。
如何解决这个问题呢?第一反应就是build过程中,想办法调用一个shell脚本,然后利用linux/unix的后台运行能力来解决这个问题。(利用nohup 或者 &):
- 创建一个shell脚本: #!/bin/bash nohup ant runserver &
- 在jenkins中,build过程中创建一个shell build step,然后直接调用这个shell脚本
感觉好像解决问题了,但是,jenkins会报错:“descriptor leak”
为什么会这样呢?官方给出了这个问题的解释:主要原因是jenkins和子进程之间是通过管道(stdin/stdout/stderr)来连接的。这样,jenkins就可以抓到子进程的输出,将它打印在自己的进程中。也正是由于这样,jenkins会一直等待子进程发送EOF信号,它才会认为子进程结束了。而利用linux的后台运行能力,主进程等不到这个EOF,于是就导致了“descriptor leak”的问题。
难道我们就束手无策了吗?其实,官方同样给出了不同系统的解决方案,其中linux就是利用 daemonize工具。这个工具主要可以把程序当成unix的daemon程序来处理,它会自动去关闭所有打开的文件描述符(file descriptor)。
有了它之后,jenkins的build进程就能够正常接收到EOF信号,并且正确的认为子进程已经结束了。然后,就可以把整个build进程结束了。具体做法就是:
- 在shell脚本中,直接调用: daemonize -o output-file absolute_path_of_the_shell_file