Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题

在上一篇文章”Jenkins的Lockable Resource插件 - 1:基本使用”中,介绍了如何在Jenkins的Freestyle Job中使用Lockable Resource。

文章末尾提到一个问题:如果一个构建所需的资源已被其他正在运行的构建锁定,它将在队列中等待该资源可用。如果此时尝试再启动同一个构建加入等待队列,则会失败。本篇主要讨论这个问题的原因以及它的解决方法。

原因分析

Jenkins和插件是开源项目。Jenkins的代码在https://github.com/jenkinsci/jenkins;Lockable Resource的代码在https://github.com/jenkinsci/lockable-resources-plugin。

大致查看了这两个项目的目录结构,浏览了几个文件,根据数据结构进行大胆地推测:

  • Jenkins 维护着一个队列,当触发一个构建时,会根据 Job 的配置(这些配置信息存储在 config.xml 文件中)创建一个构建对象并将其添加到队列中。
  • 当有可用的资源时,Jenkins 会从队列中取出一个构建对象,并将其分配给一个 Node 上的执行器。
  • 在从队列中取出对象之前,Jenkins 会检查一些条件,例如可用资源和 Lockable Resources 的要求。如果条件不满足,那么构建对象将在队列中等待。
  • 队列中的构建对象有一个 actions 成员,它记录了构建是如何被触发的。如果 Job 配置了某些特殊的行为(例如通过插件或静默期设置),可能会导致多次触发的构建被合并到一个构建对象中,此时该对象将有多个 actions。
  • 实验显示,当构建被 Lockable Resource 阻塞时,多个构建请求会合并到一个构建对象中,该对象具有多个 action。

实验:当DEMO_JOB#96正在运行时,再次点击Build Now按钮3次。Build Queue中只会出现一个构建对象。当将鼠标指向队列中的对象时,可以查看其 actions、阻塞原因和等待时间。
Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第1张图片
Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第2张图片

原因:在使用Lockable Resource插件时,加入Jenkins的队列的多个构建对象被合并为一个对象,而这个对象具有多个action。(一个源文件都没完整读过,结论纯属猜测,千万别信)

解决方法

实验:创建了一个参数化的 Jenkins 作业(添加String ParameterPARM),并多次触发构建请求,每次请求都使用不同的参数(如不同的字符串:012……)。实验的目标是观察 Jenkins 的队列行为:Jenkins 无法将参数不同的构建请求合并为队列中的一个单一构建对象,因此每次点击 Build Now,queue 中都会增加一个构建对象。

启动6个构建:PARAM依次为[0, 0, 1, 1, 2, 3]

#103: PARAM = 0 (RUNNING)
#104: PARAM = 0 (PENDING)

两个PARAM = 1的构建被合并为1个#105
#105: PARAM = 1 (PENDING) 

两个PARAM = 2的构建被合并为1个
#106: PARAM = 2 (PENDING)

Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第3张图片
把鼠标指向构建对象,可以看到参数值:
Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第4张图片
Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第5张图片

最终方案

每次为 Jenkins Job 手动填写不同的参数值是一项繁琐且容易出错的任务。为了解决这个问题,我们可以设计一个自动化的方法,使每次构建都能自动添加一个唯一的参数值。以下是实现这个目标的步骤:

  1. 在 Jenkins 中,找到并安装 Active Choice 插件。这个插件允许你动态生成输入参数的选项,这些选项可以由 Groovy 脚本生成。
  2. 安装完插件后,返回到你的 Jenkins Job 的 Configuration,选中 This project is parameterized,添加 Active Choices ParameterTIMESTAMP
  3. 参数的值选择:Groovy Script,返回的 List 只包含一个时间戳字符串:return [java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))]
  4. 因为安全的限制,需要点击 Approve script,授权 Groovy script。
    Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第6张图片
  5. 每次进入Build页面,都会自动生成一个精确到毫秒的TIMESTAMP值,点击Build按钮后,页面跳转并刷新,TIMESTAMP则自动更新。
    Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第7张图片
    运行的构建对象和Queue中的构建对象
    Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第8张图片
    Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第9张图片
    Jenkins的Lockable Resource插件 - 2:解决最多只能创建一个等待任务的问题_第10张图片

其它技巧

解决了这个问题后,我们下一篇将会介绍一些更复杂、更贴近实际的用法,敬请期待。

如果你的Jenkins已经采用了pipeline,则可以通过代码掌控一切。但是有些项目和同事仍在使用祖传的的Freestyle类型的Job,因此才会有这些实验和本文的内容,探索一下也算有趣。

你可能感兴趣的:(软件开发,jenkins,经验分享,ci/cd)