庖丁解牛:Jenkins 任务队列管理完全指南

从排队查询到精准取消,用脚本和命令行驯服构建队列

在日常的 CI/CD 运维中,Jenkins 构建队列积压是家常便饭。无论是节点故障、并发风暴,还是误触发大量参数化构建,你都需要一套快速、精准的任务队列管理手段。本文将系统讲解如何查询指定 Job 的排队任务,以及如何取消特定 ID 区间或符合任意条件的构建,重点剖析脚本控制台(Groovy)和命令行/API 两种专家级操作方式。


一、基础:理解 Jenkins 队列与任务 ID

1.1 构建队列(Build Queue)

当 Jenkins 无法立即执行一个构建(例如所有执行器繁忙,或等待节点上线)时,该构建会进入构建队列。每个队列项包含:

  • 所属任务(Job)
  • 触发原因
  • 构建参数(如果是参数化任务)
  • 一个全局唯一的 Queue ID(自增整数,代表进入队列的顺序)

1.2 任务 ID vs 构建号

  • Queue ID:排队期间的临时标识,可用于精准取消。
  • Build Number:构建开始执行后分配,并持久化在构建历史中。

二者没有直接对应关系。一个任务可能多次排队并取消,最终只有一个成功执行并获得 Build Number。


二、快速入门:Web UI 基础操作

对于临时查看和少量操作,Jenkins 原生界面足够:

  1. 查看所有排队任务 :Dashboard → 构建队列 (左侧边栏)

    列表显示任务名、预估等待时间,右侧红色 "X" 可取消单个。

  2. 查看特定任务的排队情况:进入该任务的详情页,左侧 "队列" 区域会直接显示当前该任务的排队位置(如有)。

局限:无法批量取消,无法按 ID 区间或参数筛选。


三、核心利器:脚本控制台(Script Console)

这是 Jenkins 管理员最强大的武器。通过 系统管理 → 脚本控制台 执行 Groovy 代码,可以直接操作 Jenkins 内部对象。

3.1 查询指定 Job 的所有排队任务

获取任务名、Queue ID、排队时长、等待原因等信息,为后续精准取消做准备。

groovy 复制代码
def jobName = 'my-pipeline-job'   // 替换为你的任务名
def queue = Jenkins.instance.queue

println "🔍 查询任务 '${jobName}' 的排队情况"
println "=" * 50

def items = queue.items.findAll { it.task.name == jobName }
if (items.isEmpty()) {
    println "✅ 没有排队任务"
    return
}

items.each { item ->
    println "任务全名: ${item.task.fullDisplayName}"
    println "Queue ID : ${item.id}"
    println "排队时间: ${item.getInQueueSinceString()}"
    println "等待原因: ${item.getWhy()}"
    println "构建参数: ${item.params}"
    println "-" * 50
}

3.2 取消特定 Queue ID 区间的任务

场景:某段时间触发了大量低优先级构建,ID 在 1000~2000 之间,需要批量清理。

groovy 复制代码
// ====== 配置参数 ======
def targetJob = 'my-pipeline-job'
def startId = 1000L
def endId   = 2000L
// ====================

def queue = Jenkins.instance.queue
def toCancel = queue.items.findAll { item ->
    item.task.name == targetJob && 
    item.id >= startId && 
    item.id <= endId
}

println "找到 ${toCancel.size()} 个符合区间 [${startId}, ${endId}] 的排队任务"
toCancel.each { item ->
    println "取消: ${item.task.name} (Queue ID: ${item.id})"
    queue.cancel(item)
}
println "✅ 完成"

3.3 模糊匹配任务名并取消

当你有多个类似任务(例如多分支流水线 feature/*)需要同时清理时:

groovy 复制代码
def namePattern = "feature-"   // 任务名包含该字符串
def queue = Jenkins.instance.queue

queue.items.findAll { it.task.name.contains(namePattern) }.each { item ->
    println "取消: ${item.task.name} (ID: ${item.id})"
    queue.cancel(item)
}

3.4 按构建参数精准取消

对于参数化任务,可以基于某个参数值(如 BRANCH=dev)来取消排队:

groovy 复制代码
def jobName = 'deploy-job'
def targetBranch = 'dev'

def queue = Jenkins.instance.queue
queue.items.findAll { item ->
    item.task.name == jobName && 
    item.params.any { param -> 
        param.name == 'BRANCH' && param.value == targetBranch 
    }
}.each { queue.cancel(it) }

3.5 清空整个队列(慎用!)

紧急情况下可以清空所有排队任务:

groovy 复制代码
Jenkins.instance.queue.clear()

⚠️ 安全提示 :脚本控制台需要 Overall/Administer 权限。在生产环境执行批量删除前,建议先运行查询脚本确认范围。


四、命令行与 API:自动化集成首选

当需要将队列管理集成到 Shell 脚本或平台工具(如 Ansible、Python)时,Jenkins CLI 和 REST API 是最佳选择。

4.1 Jenkins CLI

前提 :下载 jenkins-cli.jar,通常位于 http://<jenkins-url>/jnlpJars/jenkins-cli.jar

查看整个队列(简单列表)
bash 复制代码
java -jar jenkins-cli.jar -s http://localhost:8080 -auth user:token list-queue

输出示例:

复制代码
1   my-pipeline-job #1
2   another-job #12
取消指定 Queue ID 的任务

CLI 没有直接的 cancel-queue-item 命令?在较新版本中可使用以下命令:

bash 复制代码
java -jar jenkins-cli.jar -s http://localhost:8080 -auth user:token cancel-queue-item <queue-id>

如果版本较旧,可以改用 REST API(见下节)。

4.2 REST API -- 最通用

获取队列 JSON 信息
bash 复制代码
curl -u "username:apiToken" \
  "http://localhost:8080/queue/api/json?pretty=true"

返回结构示例:

json 复制代码
{
  "items": [
    {
      "id": 1234,
      "task": {
        "name": "my-pipeline-job",
        "url": "..."
      },
      "params": "...",
      "inQueueSince": 1715000000000
    }
  ]
}
使用 jq 筛选指定任务的 Queue ID
bash 复制代码
curl -s -u "user:token" "http://localhost:8080/queue/api/json" \
  | jq -r '.items[] | select(.task.name=="my-pipeline-job") | .id'
取消指定 Queue ID 的任务
bash 复制代码
curl -X POST -u "user:token" \
  "http://localhost:8080/queue/cancelItem?id=1234"
组合:取消某任务 ID>1000 的所有排队任务(Shell + jq)
bash 复制代码
jobName="my-pipeline-job"
minId=1000

curl -s -u "user:token" "http://localhost:8080/queue/api/json" \
  | jq -r --arg job "$jobName" --arg min "$minId" \
      '.items[] | select(.task.name==$job and .id>=($min|tonumber)) | .id' \
  | while read id; do
      echo "Cancelling $id"
      curl -X POST -u "user:token" "http://localhost:8080/queue/cancelItem?id=$id"
    done

4.3 使用 Python + Jenkins 库

python 复制代码
import jenkins

server = jenkins.Jenkins('http://localhost:8080', username='user', password='token')
queue_info = server.get_queue_info()

for item in queue_info:
    if item['task']['name'] == 'my-pipeline-job' and item['id'] > 1000:
        # jenkins-python 库没有直接封装 cancel,可以发送原始 POST
        server.jenkins_open(server._request('POST', f'/queue/cancelItem?id={item["id"]}'))

五、专家级实践与技巧

5.1 防止任务积压:流水线自清理

在 Jenkinsfile 中,可以在并行任务开始时自动取消当前任务的旧排队项:

groovy 复制代码
// 在 pipeline 开头执行
def cancelOldQueueItems() {
    def queue = Jenkins.instance.queue
    def myId = currentBuild.rawBuild.getQueueId()
    queue.items.findAll { it.task.name == env.JOB_NAME && it.id < myId }.each {
        println "Cancelling older queued build ${it.id}"
        queue.cancel(it)
    }
}

5.2 定时清理陈旧任务

使用 Groovy 脚本结合 Jenkins 的 cron 触发器(通过 Groovy Script 插件或直接修改 init.groovy):

groovy 复制代码
// 每小时清理排队超过 30 分钟的任务
import hudson.model.Queue
def queue = Jenkins.instance.queue
def now = System.currentTimeMillis()
queue.items.each { item ->
    if (now - item.getInQueueSince() > 30 * 60 * 1000) {
        println "Cancelling stale item ${item.id} (${item.task.name})"
        queue.cancel(item)
    }
}

5.3 安全注意事项

  • 权限控制 :以上所有操作均需要 Overall/AdministerCancel 权限。在生产环境建议使用 API Token 而非明文密码。
  • 日志审计 :Jenkins 的系统日志会记录队列取消操作。通过脚本控制台执行的操作会记录在 jenkins.log 中。
  • 测试先行:大规模取消前,先运行查询脚本确认影响范围。

六、概念关系总结

text 复制代码
+----------------+      排队时分配       +----------------+
|   Jenkins Job   | ------------------> |   Queue Item    |
|  (任务定义)      |                      |  - Queue ID     |
+----------------+                      |  - Build Params |
                                         |  - Timestamp    |
                                         +----------------+
                                                     |
                                         开始执行后转为  |
                                                     v
                                         +----------------+
                                         |   Build        |
                                         |  - Build Number|
                                         +----------------+
  • Queue ID:临时、自增、全局唯一,用于排队期管理。
  • Build Number:永久、任务内自增,用于历史追溯。
  • 脚本控制台:通过 Groovy 直接操作 Jenkins 对象模型,适合复杂筛选。
  • REST API:标准化接口,适合跨语言、跨平台集成。

七、总结

需求场景 推荐方式 核心命令/脚本
快速查看个别任务排队 Web UI 项目页面左侧"队列"
查询指定任务的所有排队项 脚本控制台 queue.items.findAll{it.task.name==...}
批量取消 ID 区间任务 脚本控制台 结合 id>=start && id<=end 过滤
按构建参数精准取消 脚本控制台 检查 item.params
清空整个队列 脚本控制台 / CLI Jenkins.instance.queue.clear() / clear-queue
集成到 Shell 脚本 REST API + curl curl -X POST /queue/cancelItem?id=...
集成到 Python 应用 python-jenkins + requests 发送原始 POST 请求

掌握脚本控制台和 REST API,你就能像管理进程一样精细操控 Jenkins 的构建队列。无论是日常运维还是应急响应,都可以做到"指哪打哪"。

最后提醒 :在脚本控制台中使用 cancel 操作前,务必先用 findAllprintln 预览结果,避免误取消重要构建。

🧠 思考:如果节点故障导致上千个任务排队,如何只取消某个特定 Git 分支的任务而保留其他?欢迎在评论区讨论。

相关推荐
X1A0RAN18 小时前
Jenkins Pipeline 变量打印指南
运维·servlet·jenkins
heimeiyingwang19 小时前
【CI/CD·Jenkins篇】多节点构建:Agent 配置与任务分发策略
ci/cd·jenkins
heimeiyingwang2 天前
【CI/CD·Jenkins篇】环境搭建:从零部署 Jenkins 主从架构
ci/cd·jenkins
heimeiyingwang2 天前
【CI/CD·Jenkins篇】Pipeline 基础:Declarative 与 Scripted 语法详解
ci/cd·pipeline·jenkins
遨游DATA3 天前
Jenkins 修改 config.xml 后页面仍是旧配置:让 live job 配置真正生效
ci/cd·jenkins·devops·故障排查·config.xml
Dobby_053 天前
【CICD】Jenkins Pipeline 快速学习入门
运维·学习·jenkins
上海安当技术4 天前
统一身份认证平台怎么落地?11 个异构业务系统接入 ASP 的完整实施路径
数据库·servlet·架构·kubernetes·jenkins
回眸不遇5 天前
Elasticsearch嵌套类型nested使用指南
大数据·elasticsearch·jenkins
回眸不遇6 天前
类型的区别和应用场景 nested 每个对象独立存储为隐藏的子文档 适合存储数组 查询的时候有特定的语法 nested查询 且字段要 ...
运维·jenkins
X1A0RAN7 天前
容器化部署 Jenkins 教程
运维·docker·jenkins