Jenkins Pipeline:如何在超时时打印挂起进程的堆栈跟踪?

时间:2018-08-27 13:46:33

标签: jenkins groovy jenkins-pipeline

在我的测试中,管道超时步骤将在挂起的进程到达catch块之前将其挂起,因此似乎无法运行“ jstack”(例如),因为为时已晚:

try{ 
  timeout(time: 3, unit: 'SECONDS') {
    sh "some slow/hanging java process"
  }
} catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
   //check that the cause is org.jenkinsci.plugins.workflow.steps.TimeoutStepExecution.ExceededTimeout
   // then try to run jstack on all java processes on the machine.
   // but that won't work because the offending process is already gone, 
   // "timeout" killed it...
}

概括地说,如何调试耗时太长的进程而又不终止进程?

我能想到的唯一解决方案确实很难看,就像这样:

def ok = false
def alarmTime = System.currentTimeMillis() + 50000 //just before timeout
parallel main: {
  timeout(60000) {
    //run java
    ok = true
  } 
}, watcher: {
  waitUntil {
    ok || System.currentTimeMillis() > alarmTime
  }
  if (!ok) {  
    //perform debugging just before timeout fires.
  }
}

但这在代码和输出中都很丑陋...

更新:我打开JENKINS-54415并提出了解决此问题的建议。

1 个答案:

答案 0 :(得分:0)

您可以使用timeout command(coreutils的一部分)来完成此操作。

示例:

timeout --preserve-status --kill-after=30m --signal=3 20m <command>

这将在20分钟后打印线程堆栈跟踪转储,并在30分钟后终止该进程。

我通常将其包装在Jenkinsfile中的一个额外的超时块中,该超时块中的超时值稍高一些,以捕获不会退出的进程。 示例:

timeout(time: 35, unit: 'MINUTES') {
  sh "timeout --preserve-status --kill-after=30m --signal=3 20m sbt test"
}