Jenkins Pipeline sleep(10) prevents function from being completed

18,492

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.

Share:
18,492

Related videos on Youtube

Seitan
Author by

Seitan

Updated on September 15, 2022

Comments

  • Seitan
    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
      Seitan almost 6 years
      This is just example. Everything below sleep is omitted. Be it println, echo or anther command.
    • towel
      towel almost 6 years
      I 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
    mkobit almost 6 years
    The 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
    Szymon Stepniak almost 6 years
    Thanks 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
    marbu almost 5 years
    Why does adding @NonCPS make the sleep end the function? I'm asking because this looks like very unexpected side effect to me.