Jenkins管道里程碑未取消先前正在进行的构建

Jenkins管道里程碑未取消先前正在进行的构建,jenkins,jenkins-pipeline,Jenkins,Jenkins Pipeline,我正在试验Jenkins管道和里程碑,无法理解为什么Jenkins在新构建跨越里程碑时不取消以前的构建 Jenkinsfile示例 pipeline { agent any parameters { booleanParam(defaultValue: true, description: '', name: 'userFlag') } stages { stage("foo") { steps {

我正在试验Jenkins管道和里程碑,无法理解为什么Jenkins在新构建跨越里程碑时不取消以前的构建

Jenkinsfile示例

pipeline {
    agent any

    parameters {
        booleanParam(defaultValue: true, description: '', name: 'userFlag')
    }

    stages {
        stage("foo") {
            steps {
                milestone(ordinal: 1, label: "BUILD_START_MILESTONE")
                sh 'sleep 1000'
            }
        }
    } 
}

触发此管道两次不会取消第一个作业

我不认为该行为是“如果我是跨越此里程碑的较新版本,则所有跨越此里程碑的较旧版本都将被取消”

里程碑步骤的实际行为是,当较新的管道首先穿过里程碑时,它会阻止较旧的管道穿过该里程碑

根据,一对“milestone()”对我来说很有用,可以在管道启动的时候杀死以前的工作

stage('Build') {    
    // The first milestone step starts tracking concurrent build order
    milestone()
    node {
        echo "Building"
    }}

// The Deploy stage does not limit concurrency but requires manual input
// from a user. Several builds might reach this step waiting for input.
// When a user promotes a specific build all preceding builds are aborted,
// ensuring that the latest code is always deployed.
stage('Deploy') {
    timeout(time: 60, unit: 'SECONDS') {input "Deploy?"}    
    milestone()
    node {
        echo "Deploying"
    }
}
最后一个里程碑有助于在达到之前的构建时终止,比如在上述情况下单击deploy按钮。或针对以下情况释放的锁定资源

// This locked resource contains both Test stages as a single concurrency Unit.
// Only 1 concurrent build is allowed to utilize the test resources at a time.
// Newer builds are pulled off the queue first. When a build reaches the
// milestone at the end of the lock, all jobs started prior to the current
// build that are still waiting for the lock will be aborted
lock(resource: 'myResource', inversePrecedence: true){
  node('test') {
    stage('Unit Tests') {
      echo "Unit Tests"
    }
    stage('System Tests') {
      echo "System Tests"
    }
  }
  milestone()
}
试试这个:

/* This method should be added to your Jenkinsfile and called at the very beginning of the build*/
@NonCPS
def cancelPreviousBuilds() {
    def jobName = env.JOB_NAME
    def buildNumber = env.BUILD_NUMBER.toInteger()
    /* Get job name */
    def currentJob = Jenkins.instance.getItemByFullName(jobName)

    /* Iterating over the builds for specific job */
    for (def build : currentJob.builds) {
        /* If there is a build that is currently running and it's not current build */
        if (build.isBuilding() && build.number.toInteger() != buildNumber) {
            /* Than stopping it */
            build.doStop()
        }
    }
}

我有一个简单的解决方案,根据:

  • 构建按顺序通过里程碑(将构建编号作为分类器字段)
  • 如果较新的版本已通过里程碑,则较旧的版本将不会继续(它们将被中止)
  • 当一个构建通过一个里程碑时,任何通过上一个里程碑但未通过此里程碑的旧构建都将被中止
  • 一旦构建通过里程碑,它将永远不会被尚未通过里程碑的新构建中止
您可以尝试以下方法:

pipeline {
    agent any
    stages {
        stage('Stop Old Build') {
            steps {
                milestone label: '', ordinal:  Integer.parseInt(env.BUILD_ID) - 1
                milestone label: '', ordinal:  Integer.parseInt(env.BUILD_ID)
            }
        }
    }
}
你可以把它放在任何管道的开头


假设你刚开始一个新的构建。第一个里程碑将用于通过#4的第二个里程碑,第二个里程碑(共#5个)将用于终止#4的进程(如果它当前正在运行)。

基于@D.W.的答案,我发现了一个简单的模式。这似乎符合D.W.的bullet#3(这是官方文件):
当一个构建通过一个里程碑时,Jenkins会中止通过上一个里程碑但不是这个里程碑的旧构建。

添加一个所有事情都将通过的早期里程碑,然后在将要等待的事情之后添加一个里程碑,使所有事情都按照您认为应该的方式工作。就我而言:

steps {
  milestone 1
  input 'ok'
  milestone 2
}
使用此创建两个活动版本,并仅批准第二个版本。您将看到第一个被自动取消,因为构建2首先通过了里程碑2。 尝试取出
里程碑1
,您将看到,当构建2通过
里程碑2
时,构建1不会被取消


添加早期里程碑满足了需求。似乎一个构建必须通过任何里程碑,新构建通过的未来里程碑才会导致其取消。

我不明白为什么会这样。根据项目
,一旦构建通过里程碑,它将永远不会被尚未通过里程碑的新构建中止。
,构建4不应该停止,因为它已经通过里程碑,即使5稍后通过它。我错过了什么?好吧,现在我想我明白了。这是因为
当一个构建通过一个里程碑时,任何通过了上一个里程碑但没有通过这个里程碑的旧构建都会被中止。
,对吗?我发现如果上一个构建在
parallel
@kivagant中执行了一些东西,那么这就不能很好地工作-我看到了同样的事情,尽管我不知道如何设置和测试它。几个星期以来,里程碑方法一直工作得很好,刚才我遇到了第一个实例,上一个构建没有取消。我的管道在多个节点上使用并行阶段。我将尝试sshepel的另一个解决方案,看看它是否更可预测。管理员可以决定是否批准或拒绝此签名。@pasquers您需要允许它。转到“管理Jenkins”->“过程中脚本批准”()@pasquers我添加了以下代码作为脚本不允许错误的解决方法:''//为脚本批准添加了导入hudson.model.Run导入org.codehaus.groovy.runtime.DefaultGroovyMethods导入jenkins.model.CauseOfInterruption$UserInterruption导入hudson.model.Executor''如果移动
里程碑()
节点
之前和
锁定
之后,会出现什么行为?只是试着去理解。我了解里程碑的用途,但我不了解它在
lock
中的使用时间。这让我很困惑。锁不是只允许一个线程(我们称之为线程)进入块吗?对——关键是已经跨越里程碑的旧版本不受影响。里程碑迫使构建按顺序进行,但一旦完成,就不会触及它们。