场景
在Hudson中新建一个Job用于构建Web工程,在Job的构建脚本的最后会启动Jetty,观察发现Jetty启动之后一小段时间,进程就终止了。
 
环境
CentOS 6,Hudson 3.0.1,Jetty 8,Oracle JDK 1.6
 
分析
刚开始在Job中启动Jetty的方式是在Ant构建脚本build.xml中调用一个shell脚本进行应用部署和容器重启。整个Job的构建过程正常,Jetty终止以后也查不到任何异常日志。
 
后来尝试在Job的build step中直接使用"Execute shell"去调用shell脚本,发现Job的Console output出现如下提示:
Process leaked file descriptors. See http://wiki.hudson-ci.org/display/HUDSON/Spawning+processes+from+build for more information
查看上面的链接以及Google相关资料,发现Hudson在Job构建结束之后,kill所有未终止的衍生进程。
 
Hudson与子进程之间使用三根管道通信(stdin/stdout/stderr),这样Hudson可以捕捉到子进程的输出。由于子进程可能往stdout写入大量数据然后立即退出,Hudson为了完整读取子进程的输出,会在用于子进程stdout的管道上等待EOF。这样,无论子进程由于什么原因退出,系统将关闭进程使用的文件描述符,因而Hudson总是可以收到EOF。
 
但是当子进程A在后台fork出另一个进程B的时候(比如启动一个daemon进程),情况就出现一些变化。由于进程B会继承进程A的文件描述符,如果进程B没有关闭这些描述符,即使进程A退出,这些描述符依然是打开的,Hudson将不会在相应管道上收到EOF。通常一个实现良好的daemon会关闭所有文件描述符以避免这个问题,但是总有一些实现没有遵循这个规则。在旧版本的Hudson上,这个问题将导致Job无法结束,Hudson一直在等待EOF;新版本则会打印出上面的"leaked file descriptors"警告,然后Job构建过程继续。
 
看来Jetty可能没有关闭继承的文件描述符,Hudson在Job构建过程结束后认为Jetty进程未终止,因而将其kill掉了。上述链接指向的Hudson wiki页面上提到可以使用daemonize工具将程序作为实现良好的daemon进程运行以避免这个问题。
 
在Hudson另一wiki页面上进一步描述了Hudson杀掉衍生进程的情况。Hudson在执行Job时会设置一系列环境变量,这些环境变量将被Job衍生出的进程继承。Hudson在kill衍生进程的时候会查看进程的环境变量,如果找到它之前设置的环境变量,则将其杀掉。Wiki上给出了一个简单的方法来避免进程被kill掉:修改Hudson设置的环境变量BUILD_ID的值,从而让Hudson认为此进程不是由Job的构建过程衍生的。如:
BUILD_ID=dontKillMe /usr/apache/bin/httpd
另外,在此wiki上还提到可以在启动Hudson的时候通过Java选项来关闭Hudson杀掉所有衍生进程的这个功能:
 java -Dhudson.util.ProcessTreeKiller.disable=true -jar hudson.war
 
解决方案
1.安装daemonize包,使用daemonize命令wrap Jetty的启动指令。
daemonize ${jetty_bin} start
2.在启动Jetty之前,修改BUILD_ID环境变量。
# set BUILD_ID, or Hudson will kill any child processes
# that are started by build steps.
BUILD_ID="dontKillMe" ${jetty_bin} start
3.设置Java选项hudson.util.ProcessTreeKiller.disable为true。
 
References
3.daemonize — A tool to run a command as a daemon.http://software.clapper.org/daemonize/
 

在Hudson Job中启动daemon进程的更多相关文章

  1. Linux中创建Daemon进程的三种方法

    什么是daemon进程? Unix/Linux中的daemon进程类似于Windows中的后台服务进程,一直在后台运行运行,例如http服务进程nginx,ssh服务进程sshd等.注意,其英文拼写为 ...

  2. erlang supervisor中启动普通的进程

    文字部分转自: http://1234n.com/?post/qou3eb supervisor的子进程 一开始使用supervisor的时候,我用的是init/1返回子进程规格列表的方式,并且所有子 ...

  3. jenkin构建项目执行脚本后,脚本中启动的进程也随之关闭的解决办法

    问题描述: 之前用jenkins构建项目(maven项目)后都是通过ssh先将war文件推送到远程服务器,然后执行远程的脚本(更新项目,重启tomcat),一直没有出现问题,今天使用jenkins构建 ...

  4. Qualcomm 8X camera daemon进程浅析

    Camera 先看一下抽象层的主要流程: 首先启动一个守护进程 int qcamsvr_start(void)( qcamsvr.c) { 1. server_fd = open(server_dev ...

  5. python中的daemon守护进程实现方法

    原文参考:http://blog.csdn.net/tao_627/article/details/49532021 守护进程是生存期长的一种进程.它们独立于控制终端并且周期性的执行某种任务或等待处理 ...

  6. Android系统在新进程中启动自定义服务过程(startService)的原理分析

    在编写Android应用程序时,我们一般将一些计算型的逻辑放在一个独立的进程来处理,这样主进程仍然可以流畅地响应界面事件,提高用户体验.Android系统为我们提供了一个Service类,我们可以实现 ...

  7. Docker学习笔记 - 在运行中的容器内启动新进程

    docker psdoker top dc1 # 容器情况# 在运行中的容器内启动新进程docker exec [-d] [-i] [-t] 容器名 [command] [args]docker ex ...

  8. 在linux中安装jdk以及tomcat并shell脚本关闭启动的进程

    在命令行模式中输入uname -a ,如下图,当界面展示i386就说明本linux系统为32版本,就在官网下载对应jdk版本,或者直接到我的网盘上下载http://pan.baidu.com/s/1c ...

  9. C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思?

    原文:C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思? 在 .NET 中创建进程时,可以传入 ProcessStartInfo ...

随机推荐

  1. selenium3.x 踏坑记

    Selenium 3.x 出来也有段时间了,有哪些坑呢? 有好长一段时间没有用selenium了.最近想用来做个web自动化的小工具.根据以往经验,firefox是不需要下载driver的.启动fir ...

  2. python cookbook第三版学习笔记十三:类和对象(三)描述器

    __get__以及__set__:假设T是一个类,t是他的实例,d是它的一个描述器属性.读取属性的时候T.d返回的是d.__get__(None,T),t.d返回的是d.__get__(t,T).说法 ...

  3. RobotFramework自动化测试框架的基础关键字(四)

    1.1.1        如何使用for循环 不管在哪种编程语言中,for循环都是必不可少的,在Robot Framework中,我们也可以使用for循环来做遍历处理. 我们用for循环对一个列表进行 ...

  4. python-希尔排序

    希尔排序 希尔排序的实质就是分组插入排序,该方法又称缩小增量排序,因DL.Shell于1959年提出而得名. 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.希尔排序是非稳定排序算法 ...

  5. Java基础之数据类型、内存、修饰符、代码块

    Java 数据类型 基本数据类型 数值:int.short.long 字符:char 布尔:boolean 引用数据类型 class(类) interface(接口) 数组[] 所占字节数(1 byt ...

  6. 最通俗易懂的javascript变量提升

    a = 'ghostwu'; var a; console.log( a ); 在我没有讲什么是变量提升,以及变量提升的规则之前, 或者你没有学习过变量提升,如果按照现有的javascript理解, ...

  7. 使用Hibernate模板调用存储过程

    前提是该Dao类已经已经继承了org.springframework.orm.hibernate5.support.HibernateDaoSupport,并且在整个项目中已经配置好了事务,或者是手动 ...

  8. hdu--4148--Length of S(n)

    #include<iostream> #include<string> #include<cstring> void priTable(); using names ...

  9. mybatis 详解(七)------一对一、一对多、多对多

    前面几篇博客我们用mybatis能对单表进行增删改查操作了,也能用动态SQL书写比较复杂的sql语句.但是在实际开发中,我们做项目不可能只是单表操作,往往会涉及到多张表之间的关联操作.那么我们如何用 ...

  10. 优化hexo访问速度-将hexo部署到云主机VPS

    写在开始 一开始将自己hexo部署到github,结果发现打开页面速度有点慢,然后又将其同时部署到coding,实现双线路访问,国内解析记录到coding,国外解析到github,这样确实网站的速度能 ...