修改Jenkins启动衍生进程的生命周期
Jenkins+jmeter 多线程测试java接口时爆错,导致无法生成html报告。
先介绍下场景:
在Jenkins中新建了一个Job,假设你在一些列Build Step之前/之后,启动了一个进程,打个比方说启动一个Jboss进程。等到Build完成,你去Console Output中查看显示启动成功,甚至PID也有了。但是当你去后台查看的时候,发现其实这个进程根本不存在,并没有启动成功。
不过如果你使用的是较早的Hudson版本(Ver 1.136),并且是直接在页面中的Build Session中(如Excute Shell)执行命令的话,你可能会得到如下的提示:
Process leaked file descriptors. See http://wiki.hudson-ci.org/display/HUDSON/Spawning+processes+from+build for more information
如果你看过这篇文章,那么你就会明白造成这种问题的原因是什么:Jenkins默认会在Build结束后Kill掉所有的衍生进程,用官方的话来说就是:
To reliably kill processes spawned by a job during a build, Jenkins contains a bit of native code to list up such processes and kill them.
问题分析:
The reason this problem happens is because of file descriptor leak and how they are inherited from one process to another. Jenkins and the child process are connected by three pipes (stdin/stdout/stderr.) This allows Jenkins to capture the output from the child process. Since the child process may write a lot of data to the pipe and quit immediately after that, Jenkins needs to make sure that it drained the pipes before it considers the build to be over. Jenkins does this by waiting for EOF.
When a process terminates for whatever reasons, the operating system closes all the file descriptors it owned. So even if the process didn't close stdout/stderr, Jenkins will nevertheless get EOF.
The complication happens when those file descriptors are inherited to other processes. Let's say the child process forks another process to the background. The background process (AKA daemon) inherits all the file descriptors of the parent, including the writing side of the stdout/stderr pipes that connect the child process and Jenkins. If the daemon forgets to close them, Jenkins won't get EOF for pipes even when the child process exits, because daemon still have those descriptors open. That's how this problem happens.
从官方的说明中可以看出,造成这种问题的原因,是由于文件描述符的丢失以及子进程是如何继承的。
Jenkins和子进程之间的通信使用三根管道进行:stdin,stdout,stderr,由于Jenkins可以捕捉到子进程的输出,而子进程可能往stdout中写入大量数据然后立即退出,Jenkins为了完整的读取子进程的输出,会在用于子进程stdout的管道上等待EOF。这样,无论子进程由于什么原因退出,系统将关闭进程使用的文件描述符,因而Jenkins总是可以收到EOF。
但是当子进程在后台fork出另一个进程的时候(比如A fork出了B,启动一个daemon进程),情况就出现一些变化。由于进程B会继承进程A的文件描述 符,如果进程B没有关闭这些描述符,即使进程A退出,这些描述符依然是打开的,Jenkins将不会在相应管道上收到EOF。
通常一个实现良好的daemon会关闭所有文件描述符以避免这个问题,但是总有一些实现没有遵循这个规则。在更旧版本的Hudson上,这个问题甚至将导致Job无法结束,Jenkins一直在那等待EOF。
解决办法:
现在我们知道,Jboss之所以没有启动成功,是因为它没有关闭继承的文件描述符,Jenkins在Job构建过程结束后认为Jboss进程未终止,因而将其kill掉了。
1. 使用daemonize工具
在这个页面中https://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build介绍了一种方法:
On Unix, you can use a wrapper like this to make the daemon behave.
在Unix上,你可以使用daemonize工具将程序作为实现良好的daemon进程运行以避免这个问题:
安装daemonize工具包,使用daemonize命令wrap 相应进程的启动指令,类似于:
- daemonize ${your.process} start
另外,页面中也给出了如何在Windows平台解决这个问题的方法,具体的看页面中的介绍就可以了。
2. 重设环境变量BUILD_ID
在研究这个问题的时候,找到了另外一篇文章:https://wiki.jenkins-ci.org/display/JENKINS/ProcessTreeKiller,这篇文章进一步描述了Hudson杀掉衍生进程的情况:
The ProcessTreeKiller takes advantage of the fact that by default a new process gets a copy of the environment variables of its spawning/creating process.
It sets a specific environment variable in the process executing the build job. Later, when the user requests to stop the build job's process it gets a list of all processes running on the computer and their environment variables, and looks for the environment variable that it initially set for the build job's process.
Every job with that environment variable in its environment is then terminated.
意思就是说,Jenkins会在执行Job时设置一系列的环境变量,这些环境变量将被Job衍生出的进程所继承。Jenkins在Kill掉衍生进程的时候会查看进程的环境变量,如果找到它之前设置的环境变量,就将其杀掉。
因此,Wiki中也给出了另外一个简单的方法来避免进程被杀掉:
A convenient way to achieve that is to change the environment variable BUILD_ID which Jenkins's ProcessTreeKiller is looking for. This will cause Jenkins to assume that your daemon is not spawned by the Jenkins build.
修改Hudson设置的环境变量BUILD_ID的值,从而让Jenkins认为此进程不是由Job的构建过程衍生的,如:
- BUILD_ID=dontKillMe /usr/apache/bin/httpd
后面的"/usr/apache/bin/httpd"可以省略,即只需要在parameter build trigger中加入一个string parameter,变量名为BUILD_ID,值为dontKillMe即可。
3. 启动时添加禁用参数
除以上两种方式以外,上面的Wiki页面中还提到了第三种解决办法,个人觉得这种方案最靠谱最彻底,不需要再去配置每个Job了:
you can disable this feature by setting a Javaproperty named "hudson.util.ProcessTree.disable" to the value "true". This can be done as a parameter to the "Java" binary when starting Jenkins:
在启动Jenkins的时候直接通过Java选项来关闭Jenkins杀掉所有衍生进程的这个功能:
- java -Dhudson.util.ProcessTree.disable=true -jar jenkins.war
- 顶
- 0
修改Jenkins启动衍生进程的生命周期的更多相关文章
- 修改jenkins启动的默认用户
# 背景 通过yum命令安装的jenkins,通过service jenkins去启动jenkins的话,默认的用户是jenkins,但jenkins这个用户是无法通过su切换过去的 ,在某些环节可能 ...
- jenkins 杀死衍生进程
解决方法-1: 在execute shell输入框中加入BUILD_ID=DONTKILLME,即可防止jenkins衍生进程 解决方法-2: 修改/etc/sysconfig/jenkins配置,在 ...
- Android进程的生命周期
Android系统想要永久的保留一个应用进程差点儿是不可能的.所以系统就须要不断的释放老的或者不太重要的进程以便腾出足够的内存空间来执行新的或者更重要的进程,那么系统怎样决定哪个进程应该保留哪个应该杀 ...
- SpringBean容器启动流程+Bean的生命周期【附源码】
如果对SpringIoc与Aop的源码感兴趣,可以访问参考:https://javadoop.com/,十分详细. 目录 Spring容器的启动全流程 Spring容器关闭流程 Bean 的生命周期 ...
- 【IOS6.0 自学瞎折腾】(五)应用程序的启动过程和Application生命周期
一 :main函数入口 看下项目资源结构,其实程序的入口也是在main.m里面. #import <UIKit/UIKit.h> #import "BvinAppDelegate ...
- JAVA Eclipse的Android的进程和生命周期是什么
安卓程序的生命周期是不受自己控制的,安卓的程序根据不同的重要性做了一些区分,最重要的进程仅仅在安卓已经崩溃或者卡死的情况下才会终止前台进程. Activity就是表现层的界面,它有三种常见的状态, ...
- iOS启动原理及应用生命周期
ios程序启动原理及生命周期图: ios应用程序的入口是main.m 1 #import <UIKit/UIKit.h> 2 3 #import "WYSAppDelegate. ...
- jenkins:通过execute shell启动的进程会被杀死的问题
[问题]在jenkins中配置自动更新部署项目时,如果采取用execute shell启动/关闭tomcat,会发现可以进行关闭tomcat,但是无法启动tomcat,虽然构建会显示执行成功,但是查看 ...
- jenkins中通过execute shell启动的进程会被杀死的问题
在jenkins中配置自动更新部署项目时,如果采取用execute shell启动/关闭tomcat,会发现可以进行关闭tomcat, 但是无法启动tomcat,虽然构建会显示执行成功,但是查看进程, ...
随机推荐
- 自定义android程序一段时间无操作后的功能
项目中遇见一个这样的需求,就是当软件在一定时间没有操作时候需要弹出广告页面,当点击广告页面时又进行软件操作,也就是广告要在软件打开并且处于未操作状态才会出来. 方法一:用handler+onTouch ...
- Oracle数据库——基本操作
一.涉及内容 1.掌握Oracle 10g 相关服务的启动.停止. 2.熟练掌握数据库配置助手(DBA).企业管理器(OEM).SQL*Plus等工具的使用. 3.掌握使用STARTUP和SHUTDO ...
- openpgp和gnupg
http://www.openpgp.org/about_openpgp/history.shtml https://www.gnupg.org/ History OpenPGP is a non-p ...
- html之input系列标签
input属性太多,我这里仅列出几个我喜欢的吧. disabled:首次加载时禁用此元素 checked:首次加载时选中此元素 form:输入字段所属的一个或多个表单 hieght:定义input字段 ...
- java中的循环
while循环: while(循环条件){ 循环操作 } 停止while循环有两种方式:1.不再满足while后的循环条件时,循环终止: ...
- web压力测试 - http_load
http_load是基于linux平台的一个性能测工具 非常小巧易用,可以用并行方式运行,来测试web服务器的性能 测试方式 (1)准备测试url vim url.txt 填写要测试的url,可以写多 ...
- Kafka 安装和测试
转载自:http://czj4451.iteye.com/blog/2041096 1. 简介 kafka (官网地址:http://kafka.apache.org)是一款分布式消息发布和订阅的系统 ...
- Hub, bridge, switch, router, gateway的区别
这些概念性的东西,其实,有的区别不是很大,有的区别很大. Hub 就是一个重复转发器,就是从一个port接受到数据后,就会原样的向其他的所有端口发送刚才收到的数据.个人理解为是工作在物理层的东西.但是 ...
- phonegap 2.7 ios配置安装详细教程(2.9通用)
原地址:http://www.cnblogs.com/yansi/archive/2013/05/14/3078222.html 在移动开发日益激烈的情况下我也不得不硬着头皮尝试下新鲜的html5的a ...
- bzoj4716 假摔
Description [题目背景] 小Q最近喜欢上了一款游戏,名为<舰队connection>,在游戏中,小Q指挥强大的舰队南征北战,从而成为了一名 dalao.在游戏关卡的攻略中,可能 ...