Skip to content

[ML] Retry 3rd-party git clones and propagate clone failures - #3233

Merged
edsavage merged 5 commits into
elastic:mainfrom
edsavage:ml/retry-3rd-party-git-clone
Oct 8, 2026
Merged

edsavage merged 5 commits into
elastic:mainfrom
edsavage:ml/retry-3rd-party-git-clone

Conversation

@edsavage

@edsavage edsavage commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Summary

The Eigen and Valijson sources are cloned at CMake configure time from
gitlab.com and github.com. Those hosts occasionally return transient errors
(e.g. GitLab "currently unable to handle this request due to load"), and a
single failed clone has been enough to break an entire CI build — see the
version-bump builds that failed on 2026-10-06 (#3290, #3291, #3292), each needing
a manual rebuild.

This PR makes the 3rd-party pull steps resilient and fail cleanly:

  • Retry with backoff. Each clone in pull-eigen.cmake and pull-valijson.cmake
    is wrapped in a bounded retry loop (5 attempts, increasing backoff), starting from
    a clean slate on every attempt (a failed clone can leave a partial directory
    behind). A brief hosting outage no longer fails the build.

  • Propagate the failure. The outer execute_process() calls in
    3rd_party/CMakeLists.txt that run these scripts previously swallowed the
    child's FATAL_ERROR: configure logged the error but continued with an empty
    3rd_party/eigen, so the failure only surfaced much later as a cryptic
    fatal error: Eigen/Core: No such file or directory compile error (exactly what
    build #3292 hit). Adding COMMAND_ERROR_IS_FATAL ANY makes configure stop
    immediately with the clear message once retries are exhausted — finally
    delivering the behaviour [ML]Fail CMake configure if 3rd-party git clone fails #3164 intended.

Test plan

  • cmake -P parse-check of both scripts (happy path, clone skipped when sources present)
  • Scratch harness exercising the retry loop against a bogus repo: confirmed N attempts, increasing backoff, final FATAL_ERROR with non-zero exit
  • Verified COMMAND_ERROR_IS_FATAL ANY aborts the parent configure when the child script fatals
  • Full CI matrix (green build exercises the happy path on every platform)

Made with Cursor

@elasticsearchmachine

Copy link
Copy Markdown

Pinging @elastic/ml-core (Team:ML)

@elasticsearchmachine

Copy link
Copy Markdown

Hi @edsavage, I've created a changelog YAML for you.

@edsavage edsavage added v8.19.24 Release version v8.19.24 v9.4.9 Release version v9.4.9 v9.5.6 Release version v9.5.6 >build and removed >enhancement labels Oct 6, 2026
edsavage added a commit to edsavage/ml-cpp that referenced this pull request Oct 6, 2026
The retry-with-backoff clone loop added in elastic#3233 was duplicated verbatim in
3rd_party/pull-eigen.cmake and 3rd_party/pull-valijson.cmake. Extract it into
ml_clone_git_dependency() in a new cmake/clone_git_dependency.cmake module that
both scripts include.

The helper lives in its own file rather than cmake/functions.cmake because the
pull-*.cmake scripts run in `cmake -P` script mode, where functions.cmake's
trailing add_custom_target() calls are invalid; a dedicated module also keeps
the change self-contained and backport-clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
@edsavage
edsavage requested a balanced review from Copilot October 6, 2026 21:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

A final failed Valijson clone can leave a directory that incorrectly suppresses cloning during the next configure.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds resilient cloning for header-only dependencies and ensures configuration stops on exhausted failures.

Changes:

  • Adds a shared bounded-retry clone helper with backoff.
  • Uses the helper for Eigen and Valijson.
  • Propagates child-script failures during configuration.
File Description
cmake/​clone_git_dependency.cmake Implements clone retries and failure reporting.
3rd_party/​pull-eigen.cmake Uses the shared helper for Eigen.
3rd_party/​pull-valijson.cmake Uses the shared helper for Valijson.
3rd_party/​CMakeLists.txt Makes clone-script failures fatal.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +68 to +70
if(NOT GIT_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to clone ${CLONE_NAME} from ${CLONE_URL} after ${CLONE_MAX_ATTEMPTS} attempts: git exited with ${GIT_RESULT}. Check network connectivity, proxy settings, and git availability.")
endif()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in f7b7d8e. The helper now removes the destination directory before raising FATAL_ERROR on exhausted retries, so a partial checkout can't cause a subsequent configure to skip the clone (which pull-valijson.cmake's existence guard would otherwise do) and fail later on missing headers. This matches the helper's "start from a clean slate on every attempt" behaviour. Verified locally: a seeded partial directory is removed when the fatal error fires.

edsavage and others added 4 commits October 7, 2026 11:14
The Eigen and Valijson sources are cloned at CMake configure time from
gitlab.com and github.com respectively. Those hosts occasionally return
transient errors (e.g. GitLab "currently unable to handle this request
due to load"), and a single failed clone was enough to break an entire
CI build, requiring a manual rebuild.

Wrap each clone in a bounded retry loop (5 attempts, increasing backoff)
that starts from a clean slate on every attempt, so a brief hosting
outage no longer fails the build.

Also propagate the failure from the outer execute_process() calls that
run these scripts. Previously the FATAL_ERROR raised inside the child
`cmake -P` process was swallowed: configure logged the error but
continued with an empty 3rd_party/eigen, so the failure only surfaced
much later as a cryptic "Eigen/Core: No such file or directory" compile
error. COMMAND_ERROR_IS_FATAL ANY makes configure stop immediately with
the clear message once retries are exhausted, finally delivering the
behaviour elastic#3164 intended.

Co-authored-by: Cursor <cursoragent@cursor.com>
The retry-with-backoff clone loop added in elastic#3233 was duplicated verbatim in
3rd_party/pull-eigen.cmake and 3rd_party/pull-valijson.cmake. Extract it into
ml_clone_git_dependency() in a new cmake/clone_git_dependency.cmake module that
both scripts include.

The helper lives in its own file rather than cmake/functions.cmake because the
pull-*.cmake scripts run in `cmake -P` script mode, where functions.cmake's
trailing add_custom_target() calls are invalid; a dedicated module also keeps
the change self-contained and backport-clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
@edsavage
edsavage force-pushed the ml/retry-3rd-party-git-clone branch from 0629022 to fd33d4e Compare October 6, 2026 22:15
…ries

If every clone attempt fails, the helper raised FATAL_ERROR without cleaning up
the destination. A partial directory left behind would cause a subsequent
configure to skip the clone (pull-valijson.cmake guards on directory existence)
and fail much later with a cryptic missing-header compile error. Remove the
destination before reporting the fatal error so the next configure re-attempts
the clone from a clean slate.

Co-authored-by: Cursor <cursoragent@cursor.com>
@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

💔 Some backports could not be created

Status Branch Result
✅ 9.5
✅ 9.4
❌ 8.19 Backport failed because of merge conflicts

Manual backport

To create the backport manually run:

backport --pr 3233

Questions ?

Please refer to the Backport tool documentation and see the Github Action logs for details

@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

💔 All backports failed

Status Branch Result
❌ 8.19 Backport failed because of merge conflicts

Manual backport

To create the backport manually run:

backport --pr 3233

Questions ?

Please refer to the Backport tool documentation and see the Github Action logs for details

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-pending >build :ml v8.19.24 Release version v8.19.24 v9.4.9 Release version v9.4.9 v9.5.6 Release version v9.5.6 v9.6.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants