从源代码出发,Jenkins 任务排队时间过长问题的解决过程

最近开发了一个部署相关的工具,使用 Jenkins 来构建应用。Jenkins 的任务从模板中创建而来。每次部署时,通过 Jenkins API 来触发构建任务。在线上运行时发现,通过 API 触发的 Jenkins 任务总是会时不时在队列中等待较长的时间。某些情况下的等待时间甚至长达几分钟。直接在 Jenkins 界面上触发的任务却几乎不需要排队,直接马上就可以执行。过长的等待时间影响了构建的效率,这是一个急需解决的问题。这个问题奇怪的地方在于,手动从界面上触发的任务几乎不需要排队,而 API 触发的任务的排队时间则完全随机,毫无规律可言。

494f9a6e5f9311d241be67ed537ad5df.jpeg

当任务在队列中时,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() 方法才被调用。

b39845fd0bd5a44deba4da73ba648e43.jpeg

继续追踪这两个方法的调用,会发现 enter() 方法在 scheduleInternal() 中被调用,用来调度新的任务。而 leave() 方法则在 maintain() 中被调用,用来在合适的时机从队列中移除任务并执行。所以看起来问题是出在 maintain() 方法中。

maintain() 方法负责维护队列,并把任务在不同的状态中移动。当有可能影响到任务调度的情况发生时,Jenkins 会在内部调用这个方法。在 scheduleInternal() 方法中,把新的任务添加到队列之后,它会调用 scheduleMaintenance() 方法提交一个 Runnable 任务来调用 maintain() 方法。

3f73c17367fecdfb82a2797b1bf69815.jpeg

经过上面的分析,任务等待时间过长的原因可能是,maintain() 方法被调用时,并没有发现处于等待的任务。所以这个任务需要等到下一次 maintain() 方法调用时才会被执行。这中间可能有与时序相关的问题。


问题找到了之后,下一步考虑的是怎么解决问题。如果要从根本上解决问题,应该从 Jenkins 入手,尝试在 Jenkins 中找到问题发生的根源,并进行修复。这种方案要求对 Jenkins 的代码库有足够程度的了解,在本地构建开发环境,并尝试稳定地复现问题。找到问题并解决之后,还需要添加 Pull Request 到 Jenkins 的代码库,并等待新版本的发布。整个过程耗时漫长。作为 Jenkins 的使用者,我自己并没有太大的意愿去花费精力在 Jenkins 自身的问题上。这种与时序有关的问题,很难复现和调试。我需要的是一个能够有效解决问题的 workaround。

前面提到了,产生问题的原因是 maintain() 方法在执行时可能没有发现等待中的任务。那么解决的办法可以很直接,那就是每次提交任务之后,等待几秒钟,再调用一次 maintain() 方法。这样就可以确保 maintain() 方法能够发现等待中的任务。maintain() 方法是由 scheduleMaintenance() 方法调用的,而 scheduleMaintenance() 是 Queue 类的一个公开方法。我只需要能够调用这个 scheduleMaintenance() 方法就可以了。

Jenkins 有一个叫做脚本控制台的功能,可以在运行的 Jenkins 实例上执行 Groovy 脚本。Groovy 脚本可以直接对运行的 Jenkins 实例进行修改。

02161d8fbd8bfb7a26137f7b158b37ea.jpeg

每个 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 任务排队时间过长的问题得到了解决。虽然并没有从根本上解决问题,但已经是一个在有限的时间内可以完成的不错的解法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/203468.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

hash_hmac函数讲解

hash_hmac函数的概述 PHP中的hash_hmac函数是一种基于加密哈希算法的函数&#xff0c;用于计算消息的哈希值。它返回一个哈希值字符串&#xff0c;并且可以用于验证消息的完整性和认证。 哈希是一种将任意长度的消息映射到固定长度的值的算法。哈希函数可以将任意大小的数据转…

我若拿出这个,阁下该如何应对,整理常用的Python库!

Requests Requests是一个常用的Python第三方库&#xff0c;用于发送HTTP请求。它提供了简洁而直观的API&#xff0c;使得发送HTTP请求变得非常方便。 使用Requests库可以实现以下功能&#xff1a; 发送GET请求&#xff1a;使用requests.get(url, paramsNone, **kwargs)方法发…

Python基础语法之学习占位符

Python基础语法之学习占位符 一、代码二、效果 一、代码 name "张三" sex "男" age 10 money 12.5# 通过占位符完成拼接 print("姓名&#xff1a;%s" % name) print("姓名&#xff1a;%s,性别&#xff1a;%s" % (name, sex))text…

maven 常用命令解析

目录 maven 是什么 Maven 目录结构 maven 常用命令解析 mvn clean mvn validate mvn compile mvn test mvn package mvn verify mvn install mvn site mvn deploy maven 是什么 Maven 是一个流行的项目管理和构建工具&#xff0c;用于帮助开发人员管理 Java 项目的…

arcgis导出某个属性的栅格

选中栅格特定属性想要导出时&#xff0c;无法选中“所选图形” 【方法】spatial analyst 工具——提取分析——按属性提取

一套后台管理系统的入门级的增删改查(vue3组合式api+elemment-plus)

一、页面示意&#xff1a; 图一 图二 二、组件结构 列表组件 &#xff1a;index.vue,对应图一添加组件&#xff1a;add.vue&#xff0c;对应图二&#xff0c;用抽屉效果编辑组件&#xff1a;edit.vue&#xff0c;和添加组件的效果一个。 三、代码 1、列表组件: index.vue …

【程序员的自我修养02】初识ELF文件格式

绪论 大家好&#xff0c;欢迎来到【程序员的自我修养】专栏。正如其专栏名&#xff0c;本专栏主要分享学习《程序员的自我修养——链接、装载与库》的知识点以及结合自己的工作经验以及思考。编译原理相关知识本身就比较有难度&#xff0c;我会尽自己最大的努力&#xff0c;争取…

卷积的理解,卷积与通道的关系

神经网络中的卷积操作卷积在图像领域的功能单通道卷积多通道卷积&#xff08;1个卷积核&#xff09;多通道卷积&#xff08;多个卷积核&#xff09;总结扩展 图像处理中的卷积核恒等&#xff08;Identity&#xff09;边缘检测&#xff08;Edge detection&#xff09;锐化&#…

SAP ABAP ALV Tree 的使用

在 SAP 业务系统中&#xff0c;大量地使用到了ALV Tree 对象&#xff0c;该对象在表格基础上对同类数据 进行归类&#xff0c;并对各分类能进行数据汇总&#xff0c;如图8-10 所示。 以航班表&#xff08;SPFLI&#xff09;为例&#xff1a; &#xff08;1&#xff09;按国家…

主流数据库类型总结

前言&#xff1a;随着互联网的高速发展&#xff0c;为了满足不同的应用场景&#xff0c;数据库的种类越来越多容易混淆&#xff0c;所以有必要在此总结一下。数据库根据数据结构可分为关系型数据库和非关系型数据库。非关系型数据库中根据应用场景又可分为键值&#xff08;Key-…

深度学习之十二(图像翻译AI算法--UNIT(Unified Neural Translation))

概念 UNIT(Unified Neural Translation)是一种用于图像翻译的 AI 模型。它是一种基于生成对抗网络(GAN)的框架,用于将图像从一个域转换到另一个域。在图像翻译中,这意味着将一个风格或内容的图像转换为另一个风格或内容的图像,而不改变图像的内容或语义。 UNIT 的核心…

微服务--06--Sentinel 限流、熔断

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.微服务保护雪崩问题服务保护方案1.1.请求限流1.2.线程隔离1.3.服务熔断 2.Sentinel2.1.介绍和安装官方网站&#xff1a;[https://sentinelguard.io/zh-cn/](https…

Windows安装EMQX(搭建MQTT服务)

1、EMQX介绍 EMQ X是云原生分布式物联网接入平台。 EMQ X (Erlang/Enterprise/Elastic MQTT Broker) 是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。 Erlang/OTP是出色的软实时 (Soft-Realtime)、低延时 (Low-Latency)、分布式 (Distributed)的语言平台。 MQTT 是…

自学MySql(一)

1.安装下载 下载网址 2、将mysql的bin目录添加到环境变量&#xff08;可选&#xff09; 3、使用一下命令测试

最新消息:滴滴 P0 事故原因,原因出来了

最新消息滴滴P0故障原因&#xff0c;是由于k8s集群升级导致的&#xff0c;后面又进行版本回退&#xff0c;由于现在大型互联网公司基本都是基于K8s进行部署的&#xff0c;如果K8s集群一出问题&#xff0c;上面运行的业务Pod和运维系统全部都得宕机&#xff0c;导致没法回滚。 …

深入理解网络阻塞 I/O:BIO

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

源码安装mysql

使用源码安装mysql&#xff0c;这里选择的版本是mysql5.7.35 ,系统是Centos7.6 官网下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 下载源码压缩包 [rootlocalhost ~]# cd /opt[rootlocalhost opt]# wget https://downloads.mysql.com/archives/get/…

一觉醒来!Keras 3.0史诗级更新,大一统深度学习三大后端框架【Tensorflow/PyTorch/Jax】

不知道大家入门上手机器学习项目是首先入坑的哪个深度学习框架&#xff0c;对于我来说&#xff0c;最先看到的听到的就是Tensorflow了&#xff0c;但是实际上手做项目开发的时候却发现了一个很重要的问题&#xff0c;不容易上手&#xff0c;基于原生的tf框架来直接开发模总是有…

ssh-keygen(centos)

A—免密登陆—>B (1)A 机器&#xff0c;通过命令”ssh-keygen -t rsa“, 生成id_rsa,id_rsa.pub authorized_keys:存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥 id_rsa : 生成的私钥文件 id_rsa.pub &#xff1a; 生成的公钥文件 know_hosts : 已知的主机公钥…

javaagent字节码增强浅尝

概述 javaagent 技术广泛应用于对代码的增强&#xff0c;比如统计方法执行时间、GC 信息打印、分布式链路跟踪等&#xff1b;实现方式包括 javassist 和 bytebuddy&#xff0c;bytebuddy 是对 javassist 的改进&#xff1b;类似于 spring 中的 AOP&#xff1b; Instrumentati…