jenkins - Jenkins pipeline throws "StackOverflowError: Excessively nested closures/functions"
问题描述
I have following Jenkinsfile
:
#!groovy
def projectPath = "${projectPath}"
def specPath = "${specPath}"
int numberOfRetries = "${NUM_OF_RETRIES}".toInteger()
def failure = true
def retryAmount = 0
def start = System.currentTimeMillis()
def getSpecName() {
specPath.split("/")[-1].split(".")[0]
}
def getProjectPath() {
projectPath.split("/")[-1]
}
def rmDocker() {
def remove = sh script: "docker rm -f cypress_${getSpecName()}", returnStatus: true
}
stage("Cypress Setup") {
node("Cypress") {
rmDocker()
}
}
stage("Cypress Run") {
node("Cypress") {
currentBuild.setDisplayName("${projectPath} - ${getSpecName()}")
while (failure && retryAmount < numberOfRetries) {
sh "docker pull dockreg.bluestembrands.com/cypresswithtests:latest"
if (getSpecName().toLowerCase().contains("auth")) {
exit_code = sh script:"docker run --name cypress_${getSpecName()} dockreg.bluestembrands.com/cypresswithtests:latest sh -c \"node SQLSite/request.js & cypress run -P ${projectPath} --spec ${specPath} --env RUN=${retryAmount} --config videoCompression=${videoCompression} --reporter /usr/local/lib/node_modules/mochawesome-cypress-bsb --reporter-options \"reportDir=mochawesome-reports/run${retryAmount}/, reportName=mochawesome\"\"", returnStatus: true
} else {
exit_code = sh script:"docker run --name cypress_${getSpecName()} dockreg.bluestembrands.com/cypresswithtests:latest sh -c \"cypress run -P ${projectPath} --spec ${specPath} --env RUN=${retryAmount} --config videoCompression=${videoCompression} --reporter /usr/local/lib/node_modules/mochawesome-cypress-bsb --reporter-options \"reportDir=mochawesome-reports/run${retryAmount}/, reportName=mochawesome\"\"", returnStatus: true
}
failure = exit_code != 0
try {
println "/var/docker-mounts/nfs/qa/test-results/${getProjectPath()}-${getSpecName()}/"
dir("/var/docker-mounts/nfs/qa/test-results/${getProjectPath()}-${getSpecName()}/") {
sh "docker cp cypress_${getSpecName()}:/cypress/${projectPath}/mochawesome-reports /var/docker-mounts/nfs/qa/test-results/${getProjectPath()}-${getSpecName()}/${BUILD_ID}"
}
} catch (Exception e) {
println e
echo "Failed to copy Mochawesome tests"
}
rmDocker()
retryAmount++
}
}
if (failure) {
currentBuild.result = "FAILURE"
}
}
It throws following exception when I try to run it:
java.lang.StackOverflowError: Excessively nested closures/functions at WorkflowScript.getProjectPath(WorkflowScript:16) - look for unbounded recursion - call depth: 1025
at com.cloudbees.groovy.cps.impl.CpsFunction.invoke(CpsFunction.java:28)
at com.cloudbees.groovy.cps.impl.CpsCallableInvocation.invoke(CpsCallableInvocation.java:40)
at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:62)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109)
at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:77)
at sun.reflect.GeneratedMethodAccessor345.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)
at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21)
at com.cloudbees.groovy.cps.Next.step(Next.java:83)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174)
at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163)
at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:122)
at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:261)
at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$101(SandboxContinuable.java:34)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.lambda$run0$0(SandboxContinuable.java:59)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox.runInSandbox(GroovySandbox.java:108)
at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:58)
at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:174)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:332)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:83)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:244)
at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:232)
at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:64)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131)
at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
The variables are:
NUM_OF_RETRIES: 3
specPath: bsb-haband-web/hab-shop/cypress/integration/Search/SearchNoResultsSpec.js
VideoCompression: false
projectPath: bsb-haband-web/hab-shop
BRANCH_NAME: master
I don't understand where the recursion call is happening as getProjectPath
just does a standard split call.
I have tried changing it to .tokenize()
, but it still fails.
It might be of note that more than one of these can run at the same times, however the error occurs even if run in isolation.
Could you please help me understanding why this StackOverflowError
happens?
解决方案
调用getProjectPath()
方法会导致此异常。发生这种情况是因为如果 Groovy 为某个字段找到了一个 getter 方法,它foo
会getFoo()
在它看到访问foo
值的任何时候回退以执行该方法。
在你的情况下是什么意思?当你调用方法时
def getProjectPath() {
projectPath.split("/")[-1]
}
它会陷入无限递归,因为这种方法被视为:
def getProjectPath() {
getProjectPath().split("/")[-1]
}
所以它永远不会达到.split("/")[-1]
- 这就是为什么用tokenize()
方法替换它并没有改变任何事情。
解决方法:重命名getProjectPath()
方法或projectPath
变量名。
Groovy 类属性
属性是类的外部可见特征。Java 中的典型约定是遵循 JavaBean 约定,即使用私有支持字段和 getter 的组合来表示属性,而不是仅仅使用公共字段来表示这些特性(这提供了更有限的抽象并会限制重构的可能性) /二传手。
来源: http: //groovy-lang.org/objectorientation.html#properties
Groovy 文档的这一部分解释了这种行为。它可以简化为一个示例 - 一个类,如:
class Person {
String name
}
被编译成这样的东西:
class Person {
private String name
void setName(String name) {
this.name = name
}
String getName() {
return this.name
}
}
使用 Groovy 时的一般经验法则是,当您指定一个字段时,foo
您会仔细实现getFoo()
(如果您确实必须这样做)。特别是您避免访问foo
此方法中的字段,因为它遇到了这个无限递归调用问题。
推荐阅读
- pandas - 熊猫中与R'频率()'命令等效的概念?
- microsoft-graph-api - 您如何从 graph-onedrive 请求新的 downloadUrl?
- python - 合并具有相同键的两个字典
- python - 对 3D 矩阵进行迭代时 Python 和 Gurobi 中的关键错误
- c# - 一次尝试捕获许多重试点
- python - Selenium Chrome 另存为 pdf 更改下载文件夹
- laravel - Laravel 5.7 成功登录后重定向到,测试问题
- c# - 如何在我的字符串值中强制使用双引号
- ios - 快速观察 UIDocumentState 的变化
- flutter - 运行应用程序时构建失败并出现异常