如何让gitlab故意重试?

Tra*_*vis 7 gitlab gitlab-ci

通过此链接, https://docs.gitlab.com/ee/ci/yaml/#retry

它表明有可能导致 gitlab 根据某些情况重试作业。这些情况列在“何时”部分。我们如何使脚本引起这些重试条件之一?

我们返回一个号码吗?我们如何找到什么数字?

由于某种原因,我们有时使用的服务永远不会被识别为可以使用,所以我想做的是检查准备情况大约 10 分钟,如果仍然失败,则使脚本失败,原因为“stuck_or_timeout_failure”然后有:

retry:
  max: 5
  when:
    - stuck_or_timeout_failure
Run Code Online (Sandbox Code Playgroud)

我如何到达那里?

Von*_*onC 5

GitLab 14.6(2021 年 12 月)会告诉您作业失败的原因:

API 响应中返回作业失败原因

使用 API 收集有关作业失败原因的数据可能很困难。
例如,您可能需要确切的失败原因,以便更好地利用关键字retry:when

现在,failure_reason作业 API 的响应中公开了这些信息,并且收集作业失败数据变得更加容易。
感谢@albert.vacacintora的贡献!

请参阅文档问题

然而,正如Ben Farmer在评论中指出的那样,这并没有解决如何告诉GitLab 作业失败的原因。

gitlab-org/gitlab Issue 262674说明它仍然是一个未实现的功能:

[gitlab-ci]使用正则表达式和/或退出代码作用于作业脚本输出日志的when“”属性的新“”值retry

作为一名开发/开发运维人员,我希望我的管道作业能够在出现功能/技术脚本错误时自动重试,这样我就不必自己动手了:)

目前 gitlab ci 中的“ retry”属性允许我们使用与 gitlab 或 gitlab-runner 错误相对应的多个“何时”,我们还希望能够根据脚本的退出代码或正则表达式来决定重试搜索作业输出日志。


stuck_or_timeout_failure标准 GitLab CI 配置尚不支持此类自定义条件,但是作为一种解决方法,当作业遇到特定故障条件(例如服务未准备好)时会重试,您可以在 CI 作业中编写该行为的脚本。
GitLab CI 中的关键字retry允许您指定应重试作业的条件。

编写一个脚本来检查服务是否准备就绪。如果服务在指定的时间范围(例如 10 分钟)内未准备好,则脚本应退出并显示非零状态代码。
Use retryin .gitlab-ci.yml**:配置retry你中的关键字.gitlab-ci.yml来响应失败。模拟自定义失败原因,例如stuck_or_timeout_failure让脚本针对此特定失败使用唯一的退出代码退出。

脚本(check_service.sh)

#!/bin/bash

# Function to check service readiness
check_service() {
    # Implement your service check logic here
    # Return 0 if ready, non-zero if not ready
}

# Try for 10 minutes
for i in {1..60}; do
    if check_service; then
        echo "Service is ready."
        exit 0
    fi
    sleep 10
done

# If service is not ready after 10 minutes, exit with a unique code (e.g., 123)
echo "Service not ready after 10 minutes."
exit 123
Run Code Online (Sandbox Code Playgroud)

.gitlab-ci.yml

job_name:
  script:
    - bash check_service.sh
  retry:
    max: 5
    when:
      - runner_system_failure
      - stuck_or_timeout_failure
Run Code Online (Sandbox Code Playgroud)

由于stuck_or_timeout_failure这不是 GitLab 认可的标准失败原因,因此它不会按预期工作。相反,当作业以非零状态代码退出时,它将重试,您可以使用它来模拟您想要的行为。

此解决方法应该允许您拥有基于服务准备情况的重试机制。如果服务在 10 分钟内未准备好,则作业最多重试 5 次。

在很多情况下,“script_failure”过于宽泛,如果发生某种预期的故障,人们希望能够在脚本中设置更具体的故障原因。我不想出于任何原因重试我的脚本,只是出于特定的预期原因。

重试根据输出日志中的特定退出代码或模式触发的作业将是解决此限制的方法,但它在 GitLab CI/CD 中尚不可用。

一个复杂的解决方法是记住失败退出代码并在后续执行中使用它是一种创造性的方法。然而,由于 CI/CD 作业的无状态性质,直接在 GitLab CI/CD 当前框架内实现它会带来挑战。GitLab CI/CD 中的每个作业执行通常都是隔离的,不会保留之前运行的状态或数据。

为了模拟这种行为,您可以使用外部系统或解决方法,例如:

  • 在外部存储退出代码:作业因特定退出代码失败后,将此代码存储在外部系统中,例如数据库、持久存储上的文件或可以在作业之间传递的工件。

  • 在后续运行中读取退出代码:在每个作业开始时,检查外部系统存储的退出代码。如果它与您感兴趣的特定故障代码匹配,则继续执行重试逻辑。如果是不同的代码,您可以中止作业或以成功状态退出。

使用 GitLab CI/CD 工件在作业之间传递退出代码的概念实现是:

  1. 第一份工作(脚本执行)

    • 执行你的脚本。
    • 将退出代码存储在文件中。
    • 将此文件设置为要传递到下一个作业的工件。
  2. 第二项工作(有条件执行)

    • 从工件中检索退出代码。
    • 仅当退出代码与特定值匹配时才执行。

这将允许后续作业检查前一个作业的退出代码并根据该代码有条件地执行。

举个例子,你的.gitlab-ci.yml情况是:

stages:
  - test
  - conditional_execution

check_service:
  stage: test
  script:
    - ./check_service.sh || echo $? > exit_code.txt
  artifacts:
    paths:
      - exit_code.txt
    expire_in: 1 hour

conditional_job:
  stage: conditional_execution
  script:
    - exit_code=$(cat exit_code.txt)
    - echo "Previous job exit code: $exit_code"
    - if [ "$exit_code" -eq "YOUR_DESIRED_EXIT_CODE" ]; then
        echo "Executing conditional job based on exit code.";
        # Place your job execution logic here
      else
        echo "Skipping execution as exit code does not match.";
      fi
  needs:
    - job: check_service
      artifacts: true
Run Code Online (Sandbox Code Playgroud)
  • check_service:该作业运行您的脚本,在 中捕获其退出代码exit_code.txt,并使该文件作为工件可用。
  • conditional_job:该作业从工件中检索退出代码。如果退出代码与所需值 ( YOUR_DESIRED_EXIT_CODE) 匹配,则继续执行其执行逻辑。否则,它会跳过执行。

这将“近似”记住特定故障代码并对其采取行动的行为。

但是,是的,GitLab 应该提供一个本机功能,使上述实现变得过时。