Jenkins Pipeline sleep(10) prevents function from being completed
Solution 1
When you call sleep(10)
inside your Groovy script, Workflow CPS plugin executes SleepStep
instead of DefaultGroovyStaticMethods.sleep(Object self, long time)
. The problem in your case is caused @NonCPS
function (thanks mkobit for a suggestion!). Consider following example:
node {
stage("Test") {
test()
}
}
@NonCPS
def test() {
echo "Start"
sleep(5)
echo "Stop"
}
Output:
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Start
[Pipeline] sleep
Sleeping for 5 sec
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
There is no Stop
echoed from the pipeline run. Now, if we only remove @NonCPS
annotation from the function we call in the pipeline:
node {
stage("Test") {
test()
}
}
def test() {
echo "Start"
sleep(5)
echo "Stop"
}
Things get change and Stop
gets echoed as expected:
Started by user admin
[Pipeline] node
Running on Jenkins in /var/jenkins_home/workspace/test-pipeline
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Test)
[Pipeline] echo
Start
[Pipeline] sleep
Sleeping for 5 sec
[Pipeline] echo
Stop
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
For more information about usage of @NonCPS
please read following Best Practices For Pipeline Code article.
Solution 2
This issue is well documented in https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches
Use of Pipeline steps from @NonCPS
Sometimes users will apply the @NonCPS annotation to a method definition, which bypasses the CPS transform inside that method. This can be done to work around limitations in Groovy language coverage (since the body of the method will execute using the native Groovy semantics), or to get better performance (the interpreter imposes a substantial overhead). However such methods must not call CPS-transformed code such as Pipeline steps.
As suggested by Szymon removing the @NonCPS tag will indeed solve the issue, however if you can't remove the @NonCPS tag because it is needed (to solve serialization issues for example) you can overcome this by using the Thread.sleep(long millis) Java method instead.
Notice - an administrator will need to approve this signature if running in sandbox.
Related videos on Youtube
Seitan
Updated on September 15, 2022Comments
-
Seitan over 1 year
I have found a strange issue with Groovy code in Jenkinsfile:
@NonCPS def test() { println "Start" sleep(10) println "Stop" }
Thing is, that after sleeping for 10s code never gets to
println "Stop"
.
It just seems, that sleep returns after 10 seconds and runs next pipeline steps.Output is just:
[Pipieline] echo Start [Pipeline] sleep Sleeping for 10 sec [Pipeline] } ... next pipeline steps
Did anyone had same problem?
-
Seitan almost 6 yearsThis is just example. Everything below
sleep
is omitted. Be itprintln
,echo
or anther command. -
towel almost 6 yearsI don't understand why "Stop" is not written (I thought at first that the last command is returned), but as a workaround you can print "Stop" from outside of the closure - not ideal, but it works :)
-
-
mkobit almost 6 yearsThe
sleep
step should work the same in scripted pipelines, at least when I have used it. I have a feeling the problem is from trying to use a pipeline step (sleep
in this case) from a@NonCPS
annotated method. Best reference I can find right now is this blog post "Gotcha: It’s not guaranteed that use of a step will generate an error (there is an open RFE to implement that), but you should not rely on that behavior. You may see improper handling of exceptions, in particular." -
Szymon Stepniak almost 6 yearsThanks a lot for the suggestion @mkobit, that was it!
sleep
step works correctly in scripted pipeline in if@NonCPS
is removed from the function. Updated the answer. -
marbu almost 5 yearsWhy does adding
@NonCPS
make the sleep end the function? I'm asking because this looks like very unexpected side effect to me.