如何在不重启服务器的情况下停止詹金斯上不可阻挡的僵尸工作?

我们的Jenkins服务器有一个已经运行了三天的作业,但是没有做任何事情。单击角落里的小X没有任何作用,控制台输出日志也没有显示任何内容。我在我们的构建服务器上检查过,该作业实际上似乎根本没有在运行。

有没有办法告诉jenkins工作已经“完成”了,比如编辑一些文件或锁之类的?因为我们有很多任务,所以我们并不想重新启动服务器。

235087 次浏览

我看了Jenkins源代码,似乎我要做的是不可能的,因为停止一个作业似乎是通过线程中断完成的。我不知道为什么这个工作被搁置了。

编辑:

就业势不可挡的可能原因:

  • 如果Jenkins陷入了无限循环,它就永远不能中止。
  • 如果Jenkins在Java虚拟机中进行网络或文件I/O(例如长时间的文件复制或SVN更新),则不能中止。

建立超时插件可以在这种情况下派上用场。如果花费太长时间,它会自动终止工作。

同样的问题已经发生在我身上两次了,唯一的解决方案是重新启动tomcat服务器并重新启动构建。

进入"Manage Jenkins" > "Script Console"在服务器上运行一个脚本以中断挂起的线程。

你可以用Thread.getAllStackTraces()获取所有活动线程,并中断正在挂起的线程。

Thread.getAllStackTraces().keySet().each() {
t -> if (t.getName()=="YOUR THREAD NAME" ) {   t.interrupt();  }
}

更新:

上述使用线程的解决方案可能不适用于最新的Jenkins版本。要中断冻结的管道,请参考解决方案(通过alexandru-bantiuc)并运行:

Jenkins.instance.getItemByFullName("JobName")
.getBuildByNumber(JobNumber)
.finish(
hudson.model.Result.ABORTED,
new java.io.IOException("Aborting build")
);

在这种情况下,我通常使用jenkins-cli。你可以从http://your-jenkins-host:PORT/cli页面下载这个罐子。然后运行

java -jar jenkins-cli.jar delete-builds name_of_job_to_delete hanging_job_number

辅助信息:

你也可以传递一系列构建,比如350:400。 通过运行

可以获得一般帮助
java -jar jenkins-cli.jar help

delete-builds by的上下文命令帮助

java -jar jenkins-cli.jar delete-builds

我使用监控插件来完成这个任务。安装插件后

  1. 转到管理Jenkins >监控Hudson/Jenkins master
  2. 展开线程的细节,即右边的蓝色小链接
  3. 查询挂起的作业名称

    线程的名称将像这样开始

    Executor #2 for master : executing <your-job-name> #<build-number> < / p >

  4. 单击所需工作所在行的表格中最右边的红色圆形按钮

我想现在回答已经太迟了,但我帮助了一些人。

  1. 安装监控插件。(http://wiki.jenkins-ci.org/display/JENKINS/Monitoring)
  2. 进入jenkinsUrl/monitoring/nodes
  3. 转到底部的Threads部分
  4. 点击主界面左侧的详细信息按钮
  5. 按用户时间排序(ms)
  6. 然后查看线程的名称,您将获得构建的名称和编号
  7. 杀了它

对不起,我没有足够的声誉来发布图片。

希望能有所帮助

我写的一个名为jkillthread的实用程序可以用来停止任何Java进程中的任何线程,只要你能用相同的帐户登录到运行该服务的机器。

你可以复制作业,然后删除旧的。如果你丢失了旧的构建日志没有关系的话。

我也有同样的问题,并修复它通过詹金斯控制台。

进入“Manage Jenkins”>“Script Console”,运行一个脚本:

 Jenkins .instance.getItemByFullName("JobName")
.getBuildByNumber(JobNumber)
.finish(hudson.model.Result.ABORTED, new java.io.IOException("Aborting build"));

您只需指定JobName和JobNumber。

有一次我遇到了一个无法通过“脚本控制台”停止的构建。最后我通过以下步骤解决了这个问题:

ssh onto the jenkins server
cd to .jenkins/jobs/<job-name>/builds/
rm -rf <build-number>
restart jenkins

如果你有一个不可阻挡的管道作业,试试下面的方法:

  1. 通过单击构建进度条旁边的红色X来终止作业
  2. 点击构建上的“Pause/resume”暂停
  3. 再次单击“暂停/恢复”以恢复构建

Pause/Resume pipeline job .

Jenkins将意识到该作业应该终止并停止构建

第一个提议的解决方案非常接近。如果使用stop()而不是interrupt(),它甚至会杀死在groovy系统脚本中无休止地运行的失控线程。这将杀死任何构建,任何工作。 代码如下:

Thread.getAllStackTraces().keySet().each() {
if (it.name.contains('YOUR JOBNAME')) {
println "Stopping $it.name"
it.stop()
}
}

Alexandru Bantiuc的回答很好地让我停止了构建,但我的执行人仍然很忙。我可以使用以下命令清除繁忙的执行程序状态

server_name_pattern = /your-servers-[1-5]/
jenkins.model.Jenkins.instance.getComputers().each { computer ->
if (computer.getName().find(server_name_pattern)) {
println computer.getName()
execList = computer.getExecutors()
for( exec in execList ) {
busyState = exec.isBusy() ? ' busy' : ' idle'
println '--' + exec.getDisplayName() + busyState
if (exec.isBusy()) {
exec.interrupt()
}
}
}
}

上面的回答几乎为我工作,但我有一个主要的问题:我有一个非常大的数量(~100)僵尸作业,由于一个特别糟糕的时间Jenkins重启,所以手动找到每个僵尸作业的作业名称和构建号,然后手动杀死它们是不可实现的。以下是我如何自动找到并杀死僵尸工作的方法:

Jenkins.instance.getItemByFullName(multibranchPipelineProjectName).getItems().each { repository->
repository.getItems().each { branch->
branch.builds.each { build->
if (build.getResult().equals(null)) {
build.doKill()
}
}
}
}

这个脚本遍历所有作业的所有构建,并使用getResult().equals(null)来确定作业是否已经完成。在队列中但尚未开始的构建将不会被迭代(因为该构建不会在job.builds中),并且已经完成的构建将为build.getResult()返回除null以外的内容。一个合法运行的作业也会有一个null的构建结果,所以在运行此作业之前,请确保没有不想杀死的正在运行的作业。

在Multibranch Pipeline项目中,多个嵌套循环主要用于发现每个存储库的每个分支/PR;如果你没有使用多分支管道,你可以直接使用Jenkins.instance.getItems().each这样的东西循环所有的作业。

以下是我如何在版本2.100与蓝海修复此问题

  • 我唯一安装的插件是bitbucket。
  • 我只有一个节点。

ssh放进我的Jenkins盒子里
cd ~/.jenkins(我保持詹金斯)
cd job/<job_name>/branches/<problem_branch_name>/builds
rm -rf <build_number> < / p > 在此之后,您可以选择更改nextBuildNumber中的数字(我这样做了)

这一步显然会有所不同,这取决于你如何管理和安装jenkins

如果你有一个Multibranch管道-job(并且你是Jenkins-admin),在Jenkins脚本控制台中使用这个脚本:

Jenkins.instance
.getItemByFullName("<JOB NAME>")
.getBranch("<BRANCH NAME>")
.getBuildByNumber(<BUILD NUMBER>)
.finish(hudson.model.Result.ABORTED, new java.io.IOException("Aborting build"));

https://issues.jenkins-ci.org/browse/JENKINS-43020

如果你不确定作业的全名(路径)是什么,你可以使用下面的代码片段列出所有项的全名:

  Jenkins.instance.getAllItems(AbstractItem.class).each {
println(it.fullName)
};

https://support.cloudbees.com/hc/en-us/articles/226941767-Groovy-to-list-all-jobs

有同样的问题,但没有堆栈线程。我们使用Jenkins控制台中的这个片段删除了作业。将jobname和build dnumber替换为您的。

def jobname = "Main/FolderName/BuildDefinition"
def buildnum = 6
Jenkins.instance.getItemByFullName(jobname).getBuildByNumber(buildnum).delete();

进入blue-ocean UI。

.

.

我有很多僵尸工作,所以我使用下面的脚本:

for(int x = 1000; x < 1813; x = x + 1) {
Jenkins .instance.getItemByFullName("JOBNAME/BRANCH")
.getBuildByNumber(x)
.finish(hudson.model.Result.ABORTED, new java.io.IOException("Aborting build"))
}

最近我遇到了一个节点/代理,它的一个执行程序被管道作业的构建“X”占用了几天,尽管该作业页面声称构建“X”不再存在(在后续10个构建后被丢弃(!),正如管道作业中配置的那样)。在磁盘上验证:构建“X”真的消失了。

解决方案:代理/节点错误地报告了被占用的执行程序正在忙着运行构建“X”。中断该执行程序的线程会立即释放它。

def executor = Jenkins.instance.getNode('NODENAME').computer.executors.find {
it.isBusy() && it.name.contains('JOBNAME')
}


println executor?.name
if (executor?.isBusy()) executor.interrupt()

考虑的其他答案:

  • 来自@cheffe的答案:没有工作(见下一点,并在下面更新)。
  • Thread.getAllStackTraces()的答案:没有匹配的线程。
  • 来自@levente-holló的答案和所有getBuildByNumber()的答案:不适用,因为构建已经不再存在了!
  • 来自@austinfromboston的答案:这接近于我的需求,但它也会破坏目前正在运行的任何其他构建。
< p > 更新: < br > 我再次经历了类似的情况,Executor被一个(仍然存在的)已完成的管道构建占用了数天。这个代码片段是唯一可行的解决方案

半小时前我也有同样的问题…

无法删除在我的多分支管道中运行的僵尸构建。 甚至服务器重启UI,甚至从命令行通过sudo service jenkins restart 阻止了行刑…建造是无法停止的……

使用版本:Jenkins 2.150.2

我很生气,但是……在查看构建日志时,我在日志的末尾发现了一些有趣的东西:

Logfile output of an zombie build and showrestart did not stop it

红色标记的部分是“令人沮丧的部分”… 正如你所看到的,我总是想要从UI中止构建,但它不起作用 但是有一个带有文本Click here to forcibly terminate running steps的超链接…(第一个绿色的) 现在我按下了链接…) 链接执行后,出现关于Still paused的消息,并显示另一个链接<代码>单击 这里强制杀死整个构建(第二个绿色的) 在按下这个链接后,构建也最终被硬杀

因此,这似乎不需要任何特殊的插件(除了多分支管道构建插件本身)。

非常简单的解决方案

我看到这个问题的原因是页面上不正确的http链接,而不是应该停止作业的https。你所需要做的就是在html页面中编辑onclick属性

  1. 打开挂起的作业(管道)的控制台日志
  2. 单击任何可用的终止作业(x图标,"单击此处强制终止运行步骤"点击这里强制杀死整个建筑”;链接可见(它是,目前是可点击的)
  3. 打开浏览器的控制台(使用任何一个铬:F12;CTRL + shift + i;菜单-更多工具-开发人员工具)
  4. 定位“点击此处强制杀死整个建筑”;手动链接或使用“在页面中选择一个元素”;控制台按钮
  5. 双击onclick属性编辑其值
  6. s附加到http以得到https
  7. 按enter键提交更改
  8. 点击“点击这里强制杀死整个建筑”;链接

参考截图 enter image description here < / p >

使用脚本控制台https://my-jenkins/script

import hudson.model.Job
import org.jenkinsci.plugins.workflow.job.WorkflowRun


Collection<Job> jobs = Jenkins.instance.getItem('My-Folder').getAllJobs()
for (int i = 0; i < jobs.size(); i++) {
def job = jobs[i]
for (int j = 0; j < job.builds.size(); j++) {
WorkflowRun build = job.builds[j]
if (build.isBuilding()) {
println("Stopping $job ${build.number}")
build.setResult(Result.FAILURE)
}
}
}

不需要使用脚本控制台或其他插件,你可以通过在浏览器中的构建URL后输入/stop/term/kill来简单地中止构建

从上述链接逐字引用:

管道作业可以通过向URL发送HTTP POST请求来停止

.构建的端点
  • BUILD ID URL>/stop -中止管道。
  • BUILD ID URL>/term -强制终止构建(只能在stop不起作用时使用。
  • BUILD ID URL>/kill -硬杀死一个管道。这是阻止管道的最具破坏性的方法,只能作为最后一种方法 李胜地。< / >

这些方法对我来说都没用。我不得不重新启动安装服务器的机器。这种杀不死的工作现在已经没有了。

这对我来说每次都很有效:

Thread.getAllStackTraces().keySet().each() {
if (it.name.contains('YOUR JOBNAME')) {
println "Stopping $it.name"
it.stop()
}
}

感谢funql.org