130

When you are using a free style project you can set that after 20 minutes the build is aborted if not concluded. How is this possible with a Jenkins Multi Branch Pipeline Project?

StephenKing
  • 36,187
  • 11
  • 83
  • 112
Devonte
  • 3,319
  • 5
  • 20
  • 15

4 Answers4

242

You can use the timeout step:

timeout(20) {
  node {
    sh 'foo'
  }
}

If you need a different TimeUnit than MINUTES, you can supply the unit argument:

timeout(time: 20, unit: 'SECONDS') {

EDIT Aug 2018: Nowadays with the more common declarative pipelines (easily recognized by the top-level pipeline construct), timeouts can also be specified using options on different levels (per overall pipeline or per stage):

pipeline {
  options {
      timeout(time: 1, unit: 'HOURS') 
  }
  stages { .. }
  // ..
}

Still, if you want to apply a timeout to a single step in a declarative pipeline, it can be used as described above.

HaaLeo
  • 10,065
  • 3
  • 44
  • 55
StephenKing
  • 36,187
  • 11
  • 83
  • 112
  • 7
    Reference is also available under 1. _Jenkins Dashboard_ → __ ▼ → _Pipeline Syntax_ → _Step Reference_ or 2. `JENKINS_URL/job//pipeline-syntax/`→ _Step Reference_. – Gerold Broser Jul 01 '16 at 10:11
  • 3
    Is it possible to only timeout fur the part of acquiring the node, and not count time spent running the contents? Ie: sometimes nodes are offline and I want a way for the job to fail if it cannot acquire a node in time, rather than timeout, but do not want the job to fail if it did acquire the node and is running.. – Jake Jan 09 '18 at 16:51
  • If you just want to know if the node is online you could you ask with: `def n=Jenkins.instance.getNode("ETService3") if (n!=null && n.computer && n.computer.online) { echo "Online" } else { echo "Offline" // wait a little bit and try again }` A tricky way ist to acquire the node twice. The first time with outer timeout, the second with inner timeout. I'm missing the feature too. – elou Apr 13 '18 at 15:10
  • 1
    @Jake, that should be a question! – charlie_pl Oct 31 '18 at 14:21
  • 1
    How do you throw your own error message when the timeout is expired? – red888 Dec 03 '18 at 20:20
  • Do you need a `returnStatus` for the `sh` inside the timeout? We seem to have problems with things succeeding and still having the timeout happen. – David West Dec 03 '18 at 21:36
  • @red888 look into the `catchError` directive, it is a fancy try/catch construct that lets you set your own message when it catches an exception. – Max Cascone Dec 16 '21 at 19:37
  • @Jake see https://stackoverflow.com/a/72665226/1655780 for a solution to the question using scripted syntax to have a timeout acquiring a node, followed by a timeout in the body. The short answer is - doubtful, that you can make timeout work like that, but the reference is a solution. – Steven the Easily Amused Jul 28 '22 at 17:33
22

For a Declarative Pipeline it is adviced to use the timeout step in the options-section.

Executes the code inside the block with a determined time out limit. If the time limit is reached, an exception (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException) is thrown, which leads in aborting the build (unless it is caught and processed somehow). Unit is optional but defaults to minutes.

The timeout-step has 3 parameters you can configure:

  • time (required, int)

    • The amount of the timeout, if no unit is stated duration in minutes
  • activity (optional, boolean)

    • Timeout after no activity in logs for this block instead of absolute duration.
  • unit (optional, values: NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS)

    • The unit for the time, default is MINUTES

Examples:

timeout(time: 10) // would lead to a timeout of 10 minutes (MINUTES is default value)
timeout(time: 10, unit: 'SECONDS') // a 10 seconds timeout
timeout(time: 10, activity: false, unit: 'MILLISECONDS')

The official Jenkins documentation has a very nice example for the use of a timeout:

pipeline {
    agent any
    options {
        timeout(time: 1, unit: 'HOURS') 
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
Michael Kemmerzell
  • 4,802
  • 4
  • 27
  • 43
  • 4
    `activity` has false as default. When `activity` is false - timeout for whole job, for `true` timeout for activity (to print anything into log). – Maxim Suslov Mar 02 '20 at 11:19
  • 2
    I want to add `timeout` for a particular stage in such a way that the subsequent stage should run gracefully. In the above example, the pipeline is aborted after the timeout and subsequent stages are not executed. Is there a way to accomplish my requirement? Sample Code for timeout of a given stage (from official Jenkins Doc): `pipeline { agent any stages { stage('Example') { options { timeout(time: 1, unit: 'HOURS') } steps { echo 'Hello World' } } } }` – Yash Mar 16 '20 at 09:35
  • 1
    It is worth note that declarative timeout for pipeline works a bit different then for stage. First one do not take into account time spent waiting for agent, second one it does. So this must be remembered when agents are heavily occupied. – Marek R Mar 19 '21 at 16:52
  • 1
    @Yash look into the `catchError` directive – Max Cascone Dec 16 '21 at 19:39
7

In a declarative pipeline you can use:

pipeline {
    agent any
    stages {
        stage('Deploy') {
            steps {
                retry(3) {
                    sh './flakey-deploy.sh'
                }

                timeout(time: 3, unit: 'MINUTES') {
                    sh './health-check.sh'
                }
            }
        }
    }
}
Aviel Yosef
  • 533
  • 5
  • 10
5

For a Declarative Pipeline (timeout for a whole job):

pipeline {
    options {
        timeout(time: 3, unit: 'HOURS')
    }
    
    agent {
        label 'agent_name'
    }
        
    stages {
        stage('Stage_name') {
            steps {
                // ...
            }
        }
    }
    
    // ...
}

For a Scripted Pipeline (timeout for a whole job):

def call() {
    node('agent_name') {
        timeout(time: 3, unit: 'HOURS') {
            stage('Stage_name') {
                // ...
            }
        }
    }    
}

Timeout inside a stage (for a specific action):

Declarative Pipeline

pipeline {
    agent {
        label 'agent_name'
    }

    stages {
        stage('Stage_name') {
            steps {
                timeout(time: 3, unit: 'HOURS') {
                    sh ' ... '
                    echo '...'
                    // ...
                }

                // ...
            }
        }
    }
}

Scripted Pipeline

def call() {
    node('agent_name') {
        stage('Stage_name') {
            timeout(time: 3, unit: 'HOURS') {
                sh '...'
                echo '...'
                // ...
            }

            // ...
        }
    }    
}
Sourav
  • 3,025
  • 2
  • 13
  • 29
cheburek
  • 101
  • 1
  • 8