从源代码出发,Jenkins 任务排队时间过长问题的解决过程
最近开发了一个部署相关的工具,使用 Jenkins 来构建应用。Jenkins 的任务从模板中创建而来。每次部署时,通过 Jenkins API 来触发构建任务。在线上运行时发现,通过 API 触发的 Jenkins 任务总是会时不时在队列中等待较长的时间。某些情况下的等待时间甚至长达几分钟。直接在 Jenkins 界面上触发的任务却几乎不需要排队,直接马上就可以执行。过长的等待时间影响了构建的效率,这是一个急需解决的问题。这个问题奇怪的地方在于,手动从界面上触发的任务几乎不需要排队,而 API 触发的任务的排队时间则完全随机,毫无规律可言。
当任务在队列中时,Jenkins 会在界面上显示该任务在队列中等待的原因。对于 API 创建的任务,它们的等待原因是“Finished waiting”。从这个原因的字面含义确实看不出来什么。当出现这样的问题时,最直接的办法是从源代码中寻找答案。
从 GitHub 上把 Jenkins 的源代码下载到本地。寻找问题的起点是搜索字符串“Finished waiting”。这个字符串定义在资源包(resource bundle)中,对应的键是 Queue.FinishedWaiting
。再搜索使用了这个键的代码,定位到了类 hudson.model.Queue
。从名字可以看出来,这个类表示的是 Jenkins 内部的工作队列。在这个类中定义了可能出现在队列中的不同类型的条目。类 WaitingItem
表示的是处于等待状态的条目。这个类的 getCauseOfBlockage()
方法刚好用到了Queue.FinishedWaiting
这个键,表示当前条目被阻塞的原因。这个 WaitingItem
类是主要的调查目标。
WaitingItem
类中有 enter()
和 leave()
两个方法,分别表示该条目进入队列和离开队列。看起来那些等待时间过长的任务,在进入了队列之后,经过很长一段时间,它们的 leave()
方法才被调用。
继续追踪这两个方法的调用,会发现 enter()
方法在 scheduleInternal()
中被调用,用来调度新的任务。而 leave()
方法则在 maintain()
中被调用,用来在合适的时机从队列中移除任务并执行。所以看起来问题是出在 maintain()
方法中。
maintain()
方法负责维护队列,并把任务在不同的状态中移动。当有可能影响到任务调度的情况发生时,Jenkins 会在内部调用这个方法。在 scheduleInternal()
方法中,把新的任务添加到队列之后,它会调用 scheduleMaintenance()
方法提交一个 Runnable
任务来调用 maintain()
方法。
经过上面的分析,任务等待时间过长的原因可能是,maintain()
方法被调用时,并没有发现处于等待的任务。所以这个任务需要等到下一次 maintain()
方法调用时才会被执行。这中间可能有与时序相关的问题。
问题找到了之后,下一步考虑的是怎么解决问题。如果要从根本上解决问题,应该从 Jenkins 入手,尝试在 Jenkins 中找到问题发生的根源,并进行修复。这种方案要求对 Jenkins 的代码库有足够程度的了解,在本地构建开发环境,并尝试稳定地复现问题。找到问题并解决之后,还需要添加 Pull Request 到 Jenkins 的代码库,并等待新版本的发布。整个过程耗时漫长。作为 Jenkins 的使用者,我自己并没有太大的意愿去花费精力在 Jenkins 自身的问题上。这种与时序有关的问题,很难复现和调试。我需要的是一个能够有效解决问题的 workaround。
前面提到了,产生问题的原因是 maintain()
方法在执行时可能没有发现等待中的任务。那么解决的办法可以很直接,那就是每次提交任务之后,等待几秒钟,再调用一次 maintain()
方法。这样就可以确保 maintain()
方法能够发现等待中的任务。maintain()
方法是由 scheduleMaintenance()
方法调用的,而 scheduleMaintenance()
是 Queue
类的一个公开方法。我只需要能够调用这个 scheduleMaintenance()
方法就可以了。
Jenkins 有一个叫做脚本控制台的功能,可以在运行的 Jenkins 实例上执行 Groovy 脚本。Groovy 脚本可以直接对运行的 Jenkins 实例进行修改。
每个 Jenkins 运行的实例中,Queue
对象只有一个。只需要找到这个 Queue
对象,并调用其中的 scheduleMaintenance()
方法,问题就解决了。脚本控制台已经内置提供了很多 Jenkins 的对象。实际上需要执行的代码很简单。
Jenkins.instance.queue.scheduleMaintenance()
通过在脚本控制台进行测试,发现只要执行了上述的脚本,原本在队列中的任务,马上就可以被调度执行。这也证明了问题确实解决了。
最后一个问题是如何把对 scheduleMaintenance()
的调用自动化,也就是在每次通过 API 触发了任务,等待几秒钟之后,自动调用 scheduleMaintenance()
方法。Jenkins 的脚本控制台并没有提供公开的 API。我采取的做法是用 HTTP 客户端模拟脚本控制台界面上的操作。脚本控制台的界面在运行脚本时,实际上执行了一个表单提交动作。这个表单被提交到了网址 <jenkins_url>/computer/(built-in)/script
,内容类型是 application/x-www-form-urlencoded
。请求中只需要包含一个参数 script
,表示需要执行的脚本内容。Jenkins 使用的是 BASIC 认证,需要把访问的用户名和密码包含在请求中。使用 HTTP 客户端模拟上述请求并不难。
下面给出了使用 Spring RestTemplate 执行 Groovy 脚本的代码示例。
var headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
var authentication = "Basic " + Base64.getEncoder().encodeToString(String.format("%s:%s", username, password).getBytes(StandardCharsets.UTF_8));
headers.add("Authorization", authentication);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("script", "Jenkins.instance.queue.scheduleMaintenance()");
var entity = new HttpEntity<>(map, headers);
try {restTemplate.exchange(String.format("%s/computer/(built-in)/script", jenkinsUrl),HttpMethod.POST, entity,String.class);
} catch (Exception e) {// 处理异常
}
至此,Jenkins 任务排队时间过长的问题得到了解决。虽然并没有从根本上解决问题,但已经是一个在有限的时间内可以完成的不错的解法。
相关文章:

从源代码出发,Jenkins 任务排队时间过长问题的解决过程
最近开发了一个部署相关的工具,使用 Jenkins 来构建应用。Jenkins 的任务从模板中创建而来。每次部署时,通过 Jenkins API 来触发构建任务。在线上运行时发现,通过 API 触发的 Jenkins 任务总是会时不时在队列中等待较长的时间。某些情况下的…...
openssl 生成CA及相关证书
实验环境:ubuntu18.04-desktop 获取openssl.cnf配置文件 # 这个返回的路径,不一定被使用了(经测试,ubuntu18下的openssl似乎未加载任何配置文件) openssl version -d生成私钥文件(pem) # 生成私钥 # genrsa…...

App测试之App日志收集及adb常用命令
文章目录 前言一、adb是什么1.APP测试收集手机日志常用的工具2.adb下载与安装3.ADT/SDK/ADB是什么4.adb连接真机 二、adb常用命令三、android系统日志文件1.logcat日志文件2.logcat日志文件分析 四、分析crash & ANR 日志1.发生crash如何分析2.发生ANR如何分析 总结扩展&am…...
【Java面试——并发基础、并发关键字】
3.1 并发基础 Java 并发 - 理论基础Java 并发 - 线程基础 多线程的出现是要解决什么问题的? 本质什么? CPU、内存、I/O 设备的速度是有极大差异的,为了合理利用 CPU 的高性能,平衡这三者的速度差异,计算机体系结构、操作系统、编译程序都…...

如何使用 Java 在Excel中创建下拉列表
下拉列表(下拉框)可以确保用户仅从预先给定的选项中进行选择,这样不仅能减少数据输入错误,还能节省时间提高效率。在MS Excel中,我们可以通过 “数据验证” 提供的选项来创建下拉列表,但如果要在Java程序中…...

Python安装步骤介绍
本文将介绍Python安装的详细步骤如下: 下载 python安装 python配置环境变量(安装时勾选配置环境变量的则无需此步骤) 一、python下载 官网:Download Python | Python.org 根据电脑位数下载所需的版本 二、Python安装 1.打开安…...
学习80min快速了解大型语言模型(ChatGPT使用)笔记
学习李宏毅:80min快速了解大型语言模型(ChatGPT使用)笔记 链接:https://www.youtube.com/watch?vwG8-IUtqu-s 1、创建一个属于自己的GPT 目前,GPT4具备一个功能,Create a GPT。利用这个功能可以创建一个…...

SQL错题集1
1.找出选修课程成绩最差的选课记录 注: 聚合函数只能用在group by和()括号中 找最值可用排序order bylimit 1 2. 查询选修成绩 合格的课程 超过2门的 学生编号 3.删除姓名为"LiMing"的学生信息 注: 删除一整行信息&…...

uniapp运行到安卓基座app/img标签不显示
img是html中的标签,他也是一个单标签 image属于服务器控件,是个双标签 问题:uniapp运行到app安卓基座后图片无法显示 原因:自己使用了img标签,而且输入路径无提示,img标签导致图片不显示 解决ÿ…...

vscode非常好用的扩展插件
1、Code Spell Checker: 帮助我们检查单词是否拼写错误,检查规则遵循驼峰拼写法。 2、Color Highlight:高亮显示颜色值 3、Svg Preview: 实时预览svg图片(修改width、height、fill等值来实时查看效果) 4、…...

一文弄懂BFS【广度优先搜索(Breadth-First Search)】
BFS,全名为广度优先搜索(Breadth-First Search),是一种用于图或树的遍历或搜索的算法。它的主要思想是由节点自身开始向它的邻居节点新进展开搜索,因此也常被形象地称为“层序遍历”。 BFS 基本思想 BFS 工作原理是,从开始节点开…...

深度学习记录--logistic回归函数的计算图
计算图用于logistic回归函数 先回顾一下单一样本的logistic回归损失函数的公式,公式如下: 将logistic函数用计算图表示出来(以两个基础量为例),计算图如下: 前向传播已经完成,接下来完成后向传播 运用链式法则依次求…...

Java基本数据类型详解
✨个人主页:全栈程序猿的CSDN博客 💨系列专栏:Java从入门到精通 ✌座右铭:编码如诗,Bug似流星,持续追求优雅的代码,解决问题如同星辰般自如 Java是一种强类型语言,数据类型在程序中起…...

第十五届蓝桥杯模拟赛(第二期)
大家好,我是晴天学长,本次分享,制作不易,本次题解只用于学习用途,如果有考试需要的小伙伴请考完试再来看题解进行学习,需要的小伙伴可以点赞关注评论一波哦!后续会继续更新第三期的。Ǵ…...
命令模式-C++实现
命令模式是一种行为型设计模式,它将请求封装成一个对象,从而能使你可以用不同的请求对客户端进行参数化。该模式允许请求的发送者和接收者进行解耦,发送者不需要知道接收者的信息,只需要通过命令对象来与它进行交互。 命令模式有…...

3dMax拼图生成工具Puzzle2D使用教程
Puzzle2D for 3dsMax拼图生成工具使用教程 Puzzle2D简介: 2D拼图随机生成器(英文:Puzzle2D) ,是一款由#沐风课堂#用MAXScript脚本语言开发的3dsMax建模小工具,可以随机创建2D可编辑样条线拼图图形。可批量…...

git报错invalid object xxx和unable to read tree xxxxxx
电脑出问题了,导致git仓库像是被损坏了一样,执行git status就会报错unable to read ree,无法正常提交代码至仓库,原因是本地代码仓库.git文件损坏了,无法找到正确的提交历史和路径。 找到了一个解决办法: …...

会泽一村民上山放羊吸烟引发森林火灾,AI科技急需关注
2023年4月,会泽县古城街道厂沟村委会望香台山林中发生了一场由疏忽引发的森林火灾。张某某在放羊时未完全熄灭烟头,导致7.33公顷的林地和草地被焚毁,直接经济损失高达29.097万元。这一事件再次凸显了日常生活中的安全隐患。 在这一背景下&…...

docker-compose部署zabbix+grafana
1.引言 1.1目的 zabbixgrafana实现图形化监控 2.部署环境 服务器ip服务版本192.168.5.137zabbix-server6.0.21192.168.5.137grafana10.2.2192.168.5.152zabbix-client6.0.21 3.部署zabbix-server 3.1 创建zabbix目录 mkdir zabbix3.2 编写docker-compose文件 cd zabbix…...
ios 逆向分分析,某业帮逆向算法(二)
接上讲 上次hook 发现自己的数据有点问题。才发现是自己的编辑器识别出问题了。 上篇sub_1029B6898函数hook数据如下: [iOS Device::作业帮 ]-> arg2: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 00000000 37 32 65 64 38 31 32 38…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...