如何在不重新启动服务器的情况下停止 Jenkins 上不可阻挡的僵尸作业?

Posted

技术标签:

【中文标题】如何在不重新启动服务器的情况下停止 Jenkins 上不可阻挡的僵尸作业?【英文标题】:How to stop an unstoppable zombie job on Jenkins without restarting the server? 【发布时间】:2013-01-05 13:37:07 【问题描述】:

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

有没有办法告诉詹金斯工作已经“完成”,通过编辑一些文件或锁或其他东西?由于我们有很多工作,我们真的不想重新启动服务器。

【问题讨论】:

似乎最新版本的 Jenkins 解决方案不是标记为已接受的解决方案。 (但 16 年的那个) 【参考方案1】:

我查看了 Jenkins 源代码,看来我想做的事情是不可能的,因为停止作业似乎是通过线程中断完成的。我不知道为什么这项工作挂了..

编辑:

无法阻止工作的可能原因:

如果 Jenkins 陷入无限循环,则永远无法中止。 如果 Jenkins 在 Java VM 中进行网络或文件 I/O(例如冗长的文件复制或 SVN 更新),则无法中止。

【讨论】:

这其实也不是不可能的。您可以使用 jenkins 脚本控制台来中断正在运行您的作业的线程。看这里的解释:***.com/a/26306081/1434041【参考方案2】:

Build-timeout Plugin 在这种情况下可以派上用场。如果时间过长,它会自动终止作业。

【讨论】:

不幸的是,这对我们来说不是一个选择,因为我们有几个工作应该运行几天(不要问) 您可以根据每个作业配置构建超时。 不,我们的构建卡住了超过 3 个小时,超时设置为 95 分钟> 【参考方案3】:

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

【讨论】:

【参考方案4】:

转到“管理 Jenkins”>“脚本控制台”在您的服务器上运行脚本以中断挂起的线程。

您可以使用Thread.getAllStackTraces() 获取所有活动线程并中断挂起的线程。

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

更新:

上述使用线程的解决方案可能不适用于更新的 Jenkins 版本。要中断冻结的管道,请参阅this 解决方案(alexandru-bantiuc),然后运行:

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

【讨论】:

效果很好!对于任何阅读的人,您可以通过首先运行上面的方法来查看线程名称,方法调用t -> println(t.getName()); 仍然无法使用上述脚本,它获取脚本但没有杀死相同的脚本。 t.getName()=="SOME NAME"中的名称匹配后是否可以打印特定线程的名称? 这对我也没有帮助 - 线程对中断()没有反应。 对我来说,中断还不够,我需要调用t.stopThread.getAllStackTraces().keySet().each() t -> if (t.getName()=="YOUR THREAD NAME" ) println(“Found, stopping now… “); t.stop(); 【参考方案5】:

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

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 的上下文命令帮助

java -jar jenkins-cli.jar delete-builds

【讨论】:

【参考方案6】:

我使用the Monitoring Plugin 来完成这项任务。安装插件后

    转到管理 Jenkins > Hudson/Jenkins master 的监控 展开主题详情,右侧的蓝色小链接

    搜索挂起的作业名称

    线程的名称将像这样开始

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

    单击表格最右侧的红色圆形按钮,位于您所需工作所在行的表中

【讨论】:

它说是被杀了,但是当我们再次刷新页面时,线程似乎还活着 有趣。我会看看这个。可能这取决于构建。如果您已经启动了外部进程,可能是通过 ANT 或 Maven 扩展,这可能会失败。 这是对我有用的解决方案。刚刚进入线程列表,搜索工作名称并单击红色按钮。 jenkinsServer/monitoring#threads【参考方案7】:

我想现在回答为时已晚,但我帮助了一些人。

    安装监控插件。 (http://wiki.jenkins-ci.org/display/JENKINS/Monitoring) 转到 jenkinsUrl/monitoring/nodes 转到底部的主题部分 点击master左侧的详情按钮 按用户时间(毫秒)排序 然后看线程的名字,就会有build的名字和编号 杀了它

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

希望对你有帮助

【讨论】:

没有帮助,它说被杀了。但是当页面重新加载时,我再次能够看到该线程 你是杀死构建的线程还是构建的子线程?这个线程的名称是什么?我猜你不会杀了好人。如果你杀死构建的线程,你会看到构建成功完成。 我尝试杀死与奴隶的执行者编号相关联的线程,该奴隶也具有作业名称。我还发现了其他几个与处理 GET 相关的线程,其中包含的信息与 Subversion 有关。杀死两者也无济于事。最后重新启动帮助了我。另一个观察结果是,没有 SVN 关联的其他线程是可以杀死的。 此答案是一个月前发布的@cheffe 答案的副本。【参考方案8】:

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

【讨论】:

【参考方案9】:

您可以复制作业并删除旧作业。如果您丢失旧的构建日志并不重要。

【讨论】:

【参考方案10】:

我也遇到了同样的问题,并通过 Jenkins 控制台解决了它。

转到“管理 Jenkins”>“脚本控制台”并运行脚本:

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

您只需指定您的 JobName 和 JobNumber。

【讨论】:

这也适用于多分支项目,但关键是将 JobName 指定为 Jenkins.instance.getItemByFullName("/") 这个答案帮助我解决了我的问题。管道完全是僵尸。上面的脚本没有工作,即使在几次 jenkins 重新启动后,管道仍在运行。我阅读了一些内部类文档并找到了一个 delete() 方法,因此我的脚本如下所示:Jenkins.instance.getItemByFullName("JobName").getBuildByNumber(JobNumber).delete(); 在执行此操作后,jenkins restart 僵尸构建终于消失了。 AbstractBuild、FreeSyleBuild 和 MavenModulesetBuild 中都没有方法 finish 我在执行这个脚本时遇到了问题,你知道吗? groovy.lang.MissingMethodException: No signature of method: hudson.model.FreeStyleBuild.finish() is applicable for argument types: (hudson.model.Result, java.io.IOException) values: [ABORTED, java.io.IOException: Aborting build] Possible solutions: find(), findAll(), find(groovy.lang.Closure) at JobName:打开项目页面并注意“项目全名”的文本【参考方案11】:

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

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

【讨论】:

在我的情况下实际上有所帮助:在通过控制台杀死它时该作业不再存在(动态管道作业,功能分支已删除) 应该是公认的答案,我尝试了几乎所有其他的,这个就像一个魅力。 这是唯一适合我的解决方案。詹金斯工作一整天,其他解决方案都不起作用。非常感谢@mugi。【参考方案12】:

如果您有不可阻挡的管道作业,请尝试以下操作:

    通过单击构建进度条旁边的红色 X 中止作业 点击构建上的“暂停/恢复”以暂停 再次单击“暂停/恢复”以恢复构建

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

【讨论】:

我没有这个菜单项。 这对我有用,并且比 Jenkins 脚本控制台侵入性更小。【参考方案13】:

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

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

【讨论】:

IMO 应该是公认的答案。所有其他答案都对我不起作用,因为构建已经处于中断状态,但是在构建后的某个步骤中挂起。只有这个解决方案确实停止了构建 在此处使用 contains 是不正确且危险的 - 如果您的作业名称为“运行测试”,它还将终止任何名为“运行测试 - 集成”、“运行测试 - 单元”等的作业. 任何使用它的人都需要注意不要意外终止无关的工作【参考方案14】:

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()
      
    
  

【讨论】:

【参考方案15】:

top answer 几乎对我有用,但我遇到了一个主要问题:由于 Jenkins 重新启动的时机特别糟糕,我有大量(约 100 个)僵尸作业,因此手动查找作业名称并构建每个僵尸作业的数量然后手动杀死它们是不可行的。以下是我自动找到并杀死僵尸作业的方法:

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 中),并且已经完成的构建将返回null 以外的其他内容build.getResult()。一个合法运行的作业也会有一个null 的构建结果,所以在运行它之前确保你没有不想杀死的正在运行的作业。

多个嵌套循环主要用于发现 Multibranch Pipeline 项目中每个存储库的每个分支/PR;如果您不使用多分支管道,您可以直接使用 Jenkins.instance.getItems().each 之类的内容循环所有作业。

【讨论】:

我稍微改进了你的脚本。 runningBuilds = Jenkins.instance.getView('All').getBuilds().findAll() it.getResult().equals(null) runningBuilds.each branch-&gt;branch.doKill() 我收到groovy.lang.MissingPropertyException: No such property: multibranchPipelineProjectName for class: Script1 这只是我使用的一个示例变量名。您必须使用您自己的多分支管道项目的名称填写它。【参考方案16】:

这是我在带有 Blue Ocean 的 2.100 版本中解决此问题的方法

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

ssh 进入我的 Jenkins 盒子 cd ~/.jenkins(我保存詹金斯的地方) cd job/&lt;job_name&gt;/branches/&lt;problem_branch_name&gt;/builds rm -rf &lt;build_number&gt;

在此之后,您可以选择更改nextBuildNumber 中的数字(我这样做了) 最后,我重启了 jenkins (brew services restart jenkins) 这一步显然会根据你管理和安装 Jenkins 的方式而有所不同。

【讨论】:

【参考方案17】:

如果您有 Multibranch Pipeline-job(并且您是 Jenkins 管理员),请在 Jenkins Script Console 中使用此脚本:

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

如果不确定作业的全名(路径)是什么,可以使用下面的sn-p列出所有项目的全名:

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

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

【讨论】:

附注:如果您使用的是 SVN(并且遵循标准约定),您的 将类似于 branches/my_branch 注意:要查看作业名称,您也可以转到作业的主页并使用“完整的项目名称:” 救命稻草。多分支管道或 Bitbucket 项目的完美解决方案【参考方案18】:

有同样的问题,但没有堆栈线程。我们在 Jenkins 控制台中使用这个 sn-p 删除了作业。用你的替换 jobname 和 build dnumber。

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

【讨论】:

这不起作用!它将仅从视图中删除构建,使正在运行的进程和所有资源锁定【参考方案19】:

进入蓝海用户界面。 尝试从那里停止工作。

【讨论】:

这是什么意思?我的 Jenkins 服务器没有这样的 UI 蓝海是一个非常常见的Jenkins插件,你可以阅读它here。 这是否真的以不同于经典 UI 的方式中止工作?这似乎令人怀疑。【参考方案20】:

我有很多僵尸作业,所以我使用了以下脚本:

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"))

【讨论】:

【参考方案21】:

最近我遇到了一个节点/代理,它有一个执行程序被管道作业的构建“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 的回答:这接近我的需求,但它也会破坏目前正在运行的任何其他构建。

更新: 我再次遇到了类似的情况,其中一个 Executor 被一个(仍然存在的)完成的管道构建占用了好几天。这段代码 sn-p 是唯一可行的解​​决方案。

【讨论】:

这对我有用,谢谢!其他解决方案不起作用,因为内部版本号已经被丢弃(我们只保留 lat 5 版本,所以 job.getBuildByNumber(...) 没有返回任何内容)。【参考方案22】:

我在最后半小时遇到了同样的问题...

无法删除在我的多分支管道中运行的僵尸构建。 甚至服务器通过 UI 重新启动,甚至通过sudo service jenkins restart 从命令行重新启动 确实阻止了执行...构建不可停止...它总是重新出现。

使用版本:Jenkins ver 2.150.2

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

红色标记的部分是“令人沮丧的部分”...... 如您所见,我一直想从 UI 中止构建,但它不起作用......

但是有一个超链接文字Click here to forcibly terminate running steps...(第一个绿色的) 现在我按下了链接...) 链接执行后,出现了一条关于 Still paused 的消息以及另一个链接 Click here to forcibily kill entire build(第二个绿色) 按下此链接后,构建最终也被硬杀......

所以这似乎在没有任何特殊插件的情况下工作(除了多分支管道构建插件本身)。

【讨论】:

如果您提供“单击此处强制终止整个构建”的链接,那么我会投票,因为这对我有用。不幸的是,这个解决方案没有,因为 Jenkins 无法显示最新的日志,因为日志文件有几个 GB。 抱歉,目前我无法再访问这些日志。如果我再次遇到此故障,我将添加评论她/更新解决方案。但是,在您的 jenkins 机器上登录并使用 tail 或日志查看器获取链接怎么样? 这对我有用,谢谢! @mjaggard:链接是:&lt;a href="#" onclick="new Ajax.Request('[server]/jenkins/job/[pipeline_name]/[job_number]/kill'); return false"&gt;Click here to forcibly kill entire build&lt;/a&gt;【参考方案23】:

非常简单的解决方案

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

    打开挂起的作业(管道)的控制台日志 单击可终止作业的任何内容(x 图标、“单击此处强制终止正在运行的步骤”等)以显示“单击此处强制终止整个构建”链接(它不会目前可点击) 打开浏览器的控制台(对 chrome 使用以下三种中的任何一种:F12;ctrl + shift + i;菜单->更多工具->开发者工具) 手动或使用控制台的“选择页面中的元素”按钮找到“单击此处强制终止整个构建”链接 双击onclick属性以编辑其值 将s 附加到http 以拥有https 按 Enter 提交更改 单击“单击此处强制终止整个构建”链接

使用截图作为参考

【讨论】:

【参考方案24】:

在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)
    
  

【讨论】:

【参考方案25】:

无需使用脚本控制台或其他插件,您只需在浏览器中的构建 URL 后输入 /stop/term/kill 即可abort a build。

从上面的链接逐字引用:

可以通过向 URL 发送 HTTP POST 请求来停止管道作业 构建的端点。

/stop - 中止管道。 /term - 强制终止构建(仅应在停止不起作用时使用。 /kill - 硬杀管道。这是停止管道的最具破坏性的方式,只能作为最后一种方式使用 度假村。

【讨论】:

【参考方案26】:

这些解决方案都不适合我。我不得不重新启动安装服务器的机器。无法杀死的工作现在已经消失了。

【讨论】:

【参考方案27】:

这对我每次都有效:

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

感谢 funql.org

【讨论】:

以上是关于如何在不重新启动服务器的情况下停止 Jenkins 上不可阻挡的僵尸作业?的主要内容,如果未能解决你的问题,请参考以下文章

无需重启即可安装 Jenkins 插件

如何在不重新启动服务器的情况下克服 Permgen 空间异常..,任何人都可以帮助我

如何在 Ubuntu 上停止 Node.js 并在不停止的情况下注销 [重复]

如何在不重新启动的情况下更新机器人状态中的“bot.users.size”

Gatsby + Contentful - 如何在不重新启动服务器的情况下在本地重做 GraphQL 查询(npm run dev)?

是否可以在不重新启动 JSF 中的服务器的情况下更新应用程序?