场景
在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. [BZOJ 4720][NOIP 2016] 换教室

    记得某dalao立了"联赛要是考概率期望我直播吃键盘"的$flag$然后就有了这道题233333 4720: [Noip2016]换教室 Time Limit: 20 Sec  M ...

  2. pwnable.kr random 之 write up

    ---恢复内容开始--- 首先看源代码: #include <stdio.h> int main(){ unsigned int random; random = rand(); // r ...

  3. word2vec原理(三) 基于Negative Sampling的模型

    word2vec原理(一) CBOW与Skip-Gram模型基础 word2vec原理(二) 基于Hierarchical Softmax的模型 word2vec原理(三) 基于Negative Sa ...

  4. 在同一个sql语句中,统计不同条件的Count数量

    前几天帮同事优化了个SQL,原写法使用多个子查询这里不再重现了,大家都遇到过这样一种情况,在项目后期的维护中, 修改别人的SQL代码,超过30行的语句,多层子查询,读起来很坑,时间久的项目伴随着人员的 ...

  5. [补档]vijos1883 月光的魔法

    vijos1883 月光的魔法 题目 传送门:https://www.vijos.org/p/1883 背景 影几欺哄了众生了 天以外-- 月儿何曾圆缺   描述 有些东西就如同月光的魔法一般. Lu ...

  6. Fail2防止sshd暴力破解

    简介: fail2ban是一款实用软件,可以监视你的系统日志,然后匹配日志的错误信息(正则式匹配)执行相应的屏蔽动作.支持大量服务.如sshd,apache,qmail,proftpd,sasl等等 ...

  7. git中常用的指令

    1.初始化仓库 git init2.设置用户名与邮箱 git config --global user.name 'name' git config --global user.email 'emai ...

  8. Open-Falcon第三步安装Agent (小米开源互联网企业级监控系统)

    安装Agent 每台机器上,都需要部署agent,agent会自动采集预先定义的各种采集项,每隔60秒,push到transfer. cd $WORKSPACE/agent/ mv cfg.examp ...

  9. NYOJ--244--16进制的简单运算(C++控制输入输出)

    16进制的简单运算 时间限制:1000 ms  |  内存限制:65535 KB 难度:1   描述 现在给你一个16进制的加减法的表达式,要求用8进制输出表达式的结果.   输入 第一行输入一个正整 ...

  10. CgLib动态代理学习【Spring AOP基础之一】

    如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...