5

Is there a way in Groovy directly or by integrating Jenkins plugins to have a downstream job complete only if it hasn't been run in the last X hours already?

Let's say I have unit tests, when green, kick off a job to create an image. I want to put an intermediary step between the two that will check to see when the last iteration of the image creation job ran, and if it was less than say 3 hours ago, NOT run the image creation job.

There isn't a way to make this work with cron that I can see, since the upstream job runs at random whenever commits are made, obfuscating any timing control. I can't just schedule the image creation because sometimes we get 10+ commits in an hour, and sometimes there's barely one a day. When that single one of the day does turn green I'd rather immediately create an image for use downstream, rather than waiting as much as 3 hours if I schedule it.

I'd prefer not to make it a 1:1 ratio commit to image only because storing them gets tricky in large numbers, and downstream from the image you'd never need them as frequently as the aforementioned 10 per hour.

Alex
  • 4,612
  • 6
  • 29
  • 49

3 Answers3

4

To synthesize Alex and Steve Johnson's answers, you could put this at the top of your downstream job:

lastBuild = currentBuild.getPreviousBuild()
delay = 2

if Date(lastBuild.timestamp) >= new Date().minusHours(delay) {
    currentBuild.result = 'SUCCESS'
    echo "Less than ${delay} hours since the last build. Job will not run."
    return
}
lawnmowerlatte
  • 442
  • 1
  • 3
  • 13
2

Took a while and it's a little on the hacky side since I'm no Groovy expert, but I got it working with this;

long now = System.currentTimeMillis()

node('jenkins2_dedicated_slave'){

    stage ('check time') {

        sh '''lastBuild=$(mktemp)

        curl -u [jenkins username]:[API key for user] "http://[jenkins URL]/[job name]/lastSuccessfulBuild/api/json" > $lastBuild

        jq -j '.timestamp' < $lastBuild > time.txt'''

    }

    archiveArtifacts artifacts: 'time.txt'
    long lastBuild = readFile('time.txt') as Long
    int finalNum = (now - lastBuild) / (1000*60*60)

    if( finalNum < 8 ) {
        currentBuild.result = 'SUCCESS'
        echo finalNum + " hours since the last build. Downstream job not run."
        return
    }

    stage ('downstream') {

        //run downstream job

    }
}

Basically this will

  1. Run a curl command on the Jenkins REST API to get the info on the last successful build and store it in a temp file

  2. Use jq to parse said info and extract the timestamp field, which is in Epoch time. This is stored to a file.

  3. The file is archived to the job and then read into a variable. This timestamp is compared to the current time, (gotten at the top of the job), and if the break between them is less than eight hours the job is "failed" out with a success and error message.

  4. If the time is over eight hours, the job continues on to build the downstream job.

Alex
  • 4,612
  • 6
  • 29
  • 49
1

This might work. I used an example X of two hours prior.

lastBuild = currentBuild.getPreviousBuild()

if Date(lastBuild.timestamp) < new Date().minusHours(2) {
  <do your thing here>
}

You may have to whitelist Date().

Cobbled together from this Cloudbees answer.