Skip to content

CI: retry git fetches and trim gRPC submodules in dependency builds - #2291

Open
Alexey-Rivkin wants to merge 1 commit into
ai-dynamo:mainfrom
Alexey-Rivkin:ci-github-clone-retry
Open

Alexey-Rivkin wants to merge 1 commit into
ai-dynamo:mainfrom
Alexey-Rivkin:ci-github-clone-retry

Conversation

@Alexey-Rivkin

@Alexey-Rivkin Alexey-Rivkin commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

What?

Retry git fetches in the dependency builds and fetch only the gRPC submodules the build uses.

Why?

  • PR builds make ~250 anonymous github.com clones; since mid-September some get refused (could not read Username), failing ~60% of nixl-ci-build-container-pr runs and a third of nixl-ci-non-gpu runs.
  • Failures are per-request, so retries absorb them and fewer clones mean fewer hits.

How?

  • .ci/scripts/retry.sh (5 attempts, backoff), copied into both images and used by .gitlab/build.sh and the container matrices, around every git clone/fetch/submodule update.
  • UCX: retry git submodule update --init before autogen.sh (its own gpunetio fetch failure is swallowed and only fails later in make).
  • gRPC: init only protobuf, c-ares, re2 and the xds proto set (SSL/Abseil/zlib are package, tests and OTel plugin off). ~26 -> 8 clones per gRPC build.
  • aws-sdk-cpp: shallow clone + retried recursive submodule init.
  • meson subprojects download taskflow prometheus-cpp under retry before meson setup.

Summary by CodeRabbit

  • Bug Fixes
    • CI builds now retry source downloads and repository operations after failures, helping builds continue through temporary network issues.
    • Some source checkouts now initialize selected submodules separately rather than fetching all recursive submodules, while retaining the required components.

@copy-pr-bot

copy-pr-bot Bot commented Sep 28, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

👋 Hi Alexey-Rivkin! Thank you for contributing to ai-dynamo/nixl.

Your PR reviewers will review your contribution then trigger the CI to test your changes.

🚀

@Alexey-Rivkin

Copy link
Copy Markdown
Contributor Author

/build

@Alexey-Rivkin
Alexey-Rivkin force-pushed the ci-github-clone-retry branch 2 times, most recently from 44c466f to e1fe3da Compare September 28, 2026 14:26
@Alexey-Rivkin

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-gpu · commit e1fe3dac

TL;DR: The Docker build for nixl-ci-gpu failed at RUN /.gitlab/build.sh because the new retry() helper in .gitlab/build.sh shells out to ../contrib/retry.sh, which does not exist inside the CI image (only /.gitlab and /.ci are copied in), so the first retry git clone exited 127. Fix by not depending on contrib/retry.sh from that path — inline the retry loop in .ci/scripts/common.sh (or copy contrib/retry.sh into the CI image / use the retry already on PATH).

Full analysis

Summary: Stage "Build Docker" (node 55) failed: Error: building at STEP "RUN /.gitlab/build.sh ${NIXL_INSTALL_DIR}": exit status 127.

Root cause: Build-log evidence (14:41:31Z, stage 55):

+ retry git clone https://github.com/abseil/abseil-cpp.git
++ dirname /.gitlab/build.sh
+ /.gitlab/../contrib/retry.sh git clone https://github.com/abseil/abseil-cpp.git
/.gitlab/build.sh: line 25: /.gitlab/../contrib/retry.sh: No such file or directory
subprocess exited with status 127

.gitlab/build.sh:25 defines retry() { "$(dirname "$0")/../contrib/retry.sh" "$@"; }. In the CI GPU image the script is executed as /.gitlab/build.sh, so that resolves to /contrib/retry.sh. The image only contains /.gitlab and /.ci (the sibling . "$(dirname "$0")/../.ci/scripts/common.sh" on line 18 resolves fine); contrib/ is not part of that image, so the helper is missing and every retry ... call dies with 127. Note contrib/Dockerfile:161 handles this correctly for the other image by doing COPY contrib/retry.sh /usr/local/bin/retry — the new .gitlab/build.sh path was never given the same treatment. This is a build-script defect, not flaky infrastructure (libfabric built and installed successfully immediately before).

Implicated commit: [REDACTED:Hex High Entropy String] — Alexey Rivkin, "CI: retry git fetches and trim gRPC submodules in dependency builds" (branch ci-github-clone-retry, PR #2291)

File: .gitlab/build.sh:25 (helper referenced: contrib/retry.sh; correct precedent at contrib/Dockerfile:161)

Suggested fix: Make the retry helper self-contained rather than path-dependent. Preferred: move the loop into .ci/scripts/common.sh, which build.sh already sources successfully at line 18:

retry() {
    for i in 1 2 3 4 5; do
        "$@" && return 0
        [ "$i" -lt 5 ] && sleep $((i * 15))
    done
    return 1
}

and delete line 25 of .gitlab/build.sh. Alternatively, have it prefer the installed binary with a fallback — retry() { if command -v retry >/dev/null 2>&1; then command retry "$@"; else "$(dirname "$0")/../contrib/retry.sh" "$@"; fi; } — and add COPY contrib/retry.sh /usr/local/bin/retry to the CI GPU Dockerfile that copies .gitlab/.ci. Either way, add a guard so a missing helper fails loudly at script start instead of on the first clone.

Related: PR #2291 (#2291) — the PR under test; this is a self-inflicted failure in that PR, not a pre-existing break.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 856e41ff-ae4c-43cb-973a-20b6f23eddef in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-test-sanitizers · commit e1fe3dac

TL;DR: The sanitizer Docker build fails at RUN /.gitlab/build.sh with exit 127 because /.gitlab/build.sh line 25 calls $(dirname $0)/../contrib/retry.sh, a helper added in this PR's commit e1fe3da that is never copied into the sanitizer build image. Either move the helper next to the already-copied .ci/scripts/common.sh or add a COPY contrib/retry.sh to the sanitizer Dockerfile (and fall back to a no-op retry if absent).

Full analysis

Summary: Stage "Build Docker" (both parallel variants, nodes 55 and 65) failed: Error: building at STEP "RUN /.gitlab/build.sh ${NIXL_INSTALL_DIR}": exit status 127.

Root cause: Deterministic missing-file error, not a hang or flake — the log shows continuous activity right up to the failure (libfabric built and installed at 14:42:18, failure 0.3 s later). The last lines are:

+ retry git clone https://github.com/abseil/abseil-cpp.git
++ dirname /.gitlab/build.sh
+ /.gitlab/../contrib/retry.sh git clone https://github.com/abseil/abseil-cpp.git
/.gitlab/build.sh: line 25: /.gitlab/../contrib/retry.sh: No such file or directory
subprocess exited with status 127

Commit e1fe3da added contrib/retry.sh and, in .gitlab/build.sh:25, defined retry() { "$(dirname "$0")/../contrib/retry.sh" "$@"; }. In the sanitizer image the script lives at /.gitlab/build.sh, so the helper is resolved to /contrib/retry.sh. The image's Dockerfile copies .gitlab and .ci into the container root (line 18's . "$(dirname "$0")/../.ci/scripts/common.sh" succeeds, proving /.ci is present) but does not copy contrib/, so /contrib/retry.sh does not exist. The same commit handled this correctly for contrib/Dockerfile only, via COPY contrib/retry.sh /usr/local/bin/retry (contrib/Dockerfile:161) — the sanitizer path was missed. The failure is in the build container itself, so no node/GPU/infra involvement.

Implicated commit: [REDACTED:Hex High Entropy String] — Alexey Rivkin, "CI: retry git fetches and trim gRPC submodules in dependency builds"

File: .gitlab/build.sh:25 (helper resolution); missing COPY of contrib/retry.sh in the sanitizer image Dockerfile (cf. contrib/Dockerfile:161)

Suggested fix: Pick one, in order of preference:

  1. Move the helper to .ci/scripts/retry.sh — that directory is already copied into every CI image (proven by the successful common.sh source at line 18) — and change line 25 to retry() { "$(dirname "$0")/../.ci/scripts/retry.sh" "$@"; }. Alternatively define the retry loop directly inside .ci/scripts/common.sh so no extra file is needed at all.
  2. Or add COPY contrib/retry.sh /usr/local/bin/retry to the sanitizer/CI Dockerfile(s) that do COPY .gitlab /.gitlab, and make line 25 resolve tolerantly:
    retry() {
        local helper="$(dirname "$0")/../contrib/retry.sh"
        if [ -x "$helper" ]; then "$helper" "$@"
        elif command -v retry.sh >/dev/null; then retry.sh "$@"
        else "$@"   # no retry helper available; don't break the build
        fi
    }
    The fallback matters: a missing convenience wrapper should never turn into exit 127 mid-build.

Related: PR #2291 (branch ci-github-clone-retry, the PR under test); prior touch of the same file 7c28a35 (#2282).

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 6049032d-68f9-4ca8-a4d1-a1daa5d6c726 in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-dl-gpu · commit e1fe3dac

TL;DR: The Setup Image aarch64/nixl-ci-dl-gpu-base Docker build died with exit 127 because .gitlab/build.sh's new retry() helper shells out to contrib/retry.sh, which is never copied into the image by .ci/dockerfiles/Dockerfile.base. Fix by copying contrib/retry.sh into the image (or inlining the retry loop as a shell function in build.sh).

Full analysis

Summary: Stage "Build Docker" (Parallel → Setup Image aarch64/nixl-ci-dl-gpu-base/0) failed while building .ci/dockerfiles/Dockerfile.base: RUN /.gitlab/build.sh ${NIXL_INSTALL_DIR} exited 127.

Root cause: Missing file inside the build context of the image, not a network/flake issue. The log shows:

+ retry git clone https://github.com/abseil/abseil-cpp.git
++ dirname /.gitlab/build.sh
+ /.gitlab/../contrib/retry.sh git clone https://github.com/abseil/abseil-cpp.git
/.gitlab/build.sh: line 25: /.gitlab/../contrib/retry.sh: No such file or directory
subprocess exited with status 127
Error: building at STEP "RUN /.gitlab/build.sh ${NIXL_INSTALL_DIR}": exit status 127

.gitlab/build.sh:25 (added on this branch) defines retry() { "$(dirname "$0")/../contrib/retry.sh" "$@"; }, i.e. it expects /contrib/retry.sh in the image. But .ci/dockerfiles/Dockerfile.base only copies .ci/scripts/, .gitlab/build.sh and one patch file (lines 71–73) — contrib/ is not copied at all. contrib/Dockerfile was updated for this (COPY contrib/retry.sh /usr/local/bin/retry, line 161), but the .ci CI Dockerfile was missed, so every dependency build that goes through Dockerfile.base fails at the first retry git clone (abseil).

Implicated commit: e1fe3dac — "CI: retry git fetches and trim gRPC submodules in dependency builds", Alexey Rivkin (PR #2291)

File: .gitlab/build.sh:25 (consumer) / .ci/dockerfiles/Dockerfile.base:71-73 (missing COPY)

Suggested fix: Either

  1. Copy the helper in Dockerfile.base alongside the other CI files, and include it in the cleanup step:
    COPY --chown="${_UID}":"${_GID}" contrib/retry.sh /contrib/retry.sh
    ...
    RUN sudo rm -rf /.gitlab/build.sh /.ci/scripts/ /contrib/
    (check any other Dockerfiles that RUN /.gitlab/build.sh need the same), or
  2. Preferably, make build.sh self-contained — drop the external dependency and inline the loop, e.g. put in .ci/scripts/common.sh (already sourced at line 18) or directly in build.sh:
    retry() { for i in 1 2 3 4 5; do "$@" && return 0; [ "$i" -lt 5 ] && sleep $((i*15)); done; return 1; }
    This removes the path/packaging coupling that broke here.

Related: PR #2291 (#2291)

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-dl-gpu-ep · commit e1fe3dac

TL;DR: The Build Docker stage died at RUN /.gitlab/build.sh because the new retry() helper in .gitlab/build.sh invokes $(dirname $0)/../contrib/retry.sh → /contrib/retry.sh, which does not exist inside the build image (only /.gitlab and /.ci are copied in), so the first retry git clone abseil-cpp exited 127. Fix: ship contrib/retry.sh into the image (e.g. COPY contrib/retry.sh /usr/local/bin/retry) and call retry from PATH instead of a relative sibling path.

Full analysis

Summary: nixl-ci-dl-gpu-ep #1326 failed in stage Build Docker (node 57): building at STEP "RUN /.gitlab/build.sh ${NIXL_INSTALL_DIR}": exit status 127.

Root cause: Not infra, not a timeout — a missing-file error in the new retry plumbing. The build image ran /.gitlab/build.sh, which defines retry() { "$(dirname "$0")/../contrib/retry.sh" "$@"; }. With $0 = /.gitlab/build.sh, that expands to /contrib/retry.sh. The image only has the .gitlab (and .ci, used successfully for common.sh) trees copied to /, not contrib/, so the very first use of the helper failed:

+ retry git clone https://github.com/abseil/abseil-cpp.git
+ /.gitlab/../contrib/retry.sh git clone https://github.com/abseil/abseil-cpp.git
/.gitlab/build.sh: line 25: /.gitlab/../contrib/retry.sh: No such file or directory
subprocess exited with status 127
Error: building at STEP "RUN /.gitlab/build.sh ${NIXL_INSTALL_DIR}": exit status 127

Everything before it (libfabric 2.7.0 download/configure/make/install, azurite npm install) completed normally, and log timestamps are continuous — no hang, no node problem. Note that contrib/Dockerfile does it correctly (COPY contrib/retry.sh /usr/local/bin/retry, line 161), so only the .gitlab/build.sh path is broken.

Implicated commit: [REDACTED:Hex High Entropy String] — "CI: retry git fetches and trim gRPC submodules in dependency builds", Alexey Rivkin (adds both contrib/retry.sh and the retry() wrapper)

File: .gitlab/build.sh:25 (helper defined) / first use at the abseil clone; contrib/retry.sh is the file that isn't present in the image

Suggested fix: Make the helper independent of the repo layout inside the image. Two changes, either of which resolves it (do both for robustness):

  1. In the Dockerfile used by the dl-gpu-ep job (the one with COPY .gitlab /.gitlab / COPY .ci /.ci and RUN /.gitlab/build.sh ...), add COPY contrib/retry.sh /usr/local/bin/retry and RUN chmod +x /usr/local/bin/retry before that RUN, mirroring contrib/Dockerfile:161.
  2. Make .gitlab/build.sh tolerant of a missing helper, e.g.:
    RETRY_SH="$(command -v retry || true)"
    [ -x "$RETRY_SH" ] || RETRY_SH="$(dirname "$0")/../contrib/retry.sh"
    retry() { if [ -x "$RETRY_SH" ]; then "$RETRY_SH" "$@"; else "$@"; fi; }
    so a build context without contrib/ degrades to a single attempt rather than exit 127.

Also worth grepping the other CI Dockerfiles/scripts touched by e1fe3da for the same ../contrib/retry.sh assumption before re-running.

Related: PR #2291 (branch ci-github-clone-retry, the change under test); related retry/clone work in PR #2263 "ci: authenticate third-party github.com clones"

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 8f9e191b-c9f9-456c-b8cd-34afe655ea64 in the triage console for the audit trail.

@Alexey-Rivkin

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-build-container-pr · commit 9b0d412b

TL;DR: Every parallel branch of build #800 failed because contrib/retry.sh — newly referenced by both the Jenkins pipeline and contrib/Dockerfile in commit 9b0d412 — is not present in the tree; add/commit the script (with the exec bit) and re-run.

Full analysis

Summary: All four parallel branches failed: "Prepare environment" with contrib/retry.sh: No such file or directory and "Build image" with Error: building at STEP "COPY contrib/retry.sh /usr/local/bin/retry" ... copier: stat: "/contrib/retry.sh": no such file or directory.

Root cause: Commit 9b0d412 ("CI: retry git fetches and trim gRPC submodules in dependency builds", branch ci-github-clone-retry, PR #2291) introduces a new helper contrib/retry.sh and consumes it from two places — the Jenkins stage script (script.sh.copy: line 6: contrib/retry.sh) and Dockerfile step 32/74 (COPY contrib/retry.sh /usr/local/bin/retry) — but the script file itself was never added to the commit. The checkout at 9b0d412 therefore has no contrib/retry.sh (confirmed: the path is unreadable in the repo), so the shell invocation fails immediately in "Prepare environment" (1.5–1.9 s) and podman's COPY fails after ~4.7 min of otherwise-healthy image build (the log shows continuous progress up to STEP 32 — no hang, no timeout, no infra fault).

Implicated commit: 9b0d412 — Alexey Rivkin, 2026-09-28T14:23:40Z

File: contrib/Dockerfile (step 32/74: COPY contrib/retry.sh /usr/local/bin/retry) and the Prepare environment pipeline step that calls contrib/retry.sh (script line 6)

Suggested fix: git add contrib/retry.sh && chmod +x contrib/retry.sh and amend/append to the PR branch — the file is referenced but untracked. Then verify locally with git ls-files contrib/retry.sh before pushing. Also worth hardening the Dockerfile so a missing helper fails with a clear message (or guard the pipeline call with [ -x contrib/retry.sh ]), and consider COPY contrib/retry.sh /usr/local/bin/retry being paired with an explicit RUN chmod +x /usr/local/bin/retry so the image doesn't depend on the committed mode bits.

Related: PR #2291 — #2291

@Alexey-Rivkin

Copy link
Copy Markdown
Contributor Author

/build

@Alexey-Rivkin

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-build-container-pr · commit ca8e8279

TL;DR: PR #2291's new retry wrapper broke the container builds: two variants die with retry: command not found (exit 127) in the ucx_custom_image stage, which starts from a base that never received the COPY .ci/scripts/retry.sh /usr/local/bin/retry, and the other two die because retry git clone https://github.com/abseil/abseil-cpp.git is refused by github.com 5/5 times (credential prompt). Fix: copy/install the retry helper into every build stage that uses it (or inline the retry loop), and don't rely on unauthenticated in-container GitHub clones.

Full analysis

Summary: All four parallel "Build image" stages of nixl-ci-build-container-pr #803 failed — two at the custom-UCX stage with /bin/bash: line 1: retry: command not found (exit 127), two at the Abseil build step with fatal: could not read Username for 'https://github.com' after 5 retries.

Root cause:

  1. Commit ca8e827 ("CI: retry git fetches and trim gRPC submodules in dependency builds") added .ci/scripts/retry.sh, installed it with a single COPY .ci/scripts/retry.sh /usr/local/bin/retry (contrib/Dockerfile:161), and then prefixed git invocations with retry throughout the build. The multi-stage CI-container build has a later stage, ucx_custom_image ([4/5] STEP 6/6, the stage that does COPY --from=ucx . /workspace/ucx and then retry git submodule update --init), whose base image does not contain /usr/local/bin/retry. Result: retry: command not found → subprocess exited with status 127 → Error: building at STEP "RUN echo \"INFO: Starting custom UCX build...\" ...". This is reproducible on both x86_64 and arm64 variants (stages 222 and 233), and it is purely a code defect in this PR.
  2. In the other two variants (stages 174 and 211) the build reached [2/2] STEP 33/74: RUN retry git clone https://github.com/abseil/abseil-cpp.git ... and the clone failed identically on all five retry attempts (15:11:02 → 15:13:35):
    Cloning into 'abseil-cpp'... / fatal: could not read Username for 'https://github.com': No such device or address / fatal: expected flush after ref listing.
    Git only prompts for a username when the smart-HTTP endpoint answers with an auth challenge, so anonymous GitHub cloning from inside the build container was being refused/intercepted for the whole 2.5-minute window (apt/wget to archive.ubuntu.com and mellanox.com in the same step worked fine, so this is specific to github.com egress, not general connectivity). The retry wrapper cannot mask a sustained refusal — it just turned one hard failure into five.

Implicated commit: [REDACTED:Hex High Entropy String] — Alexey Rivkin, "CI: retry git fetches and trim gRPC submodules in dependency builds"

File: contrib/Dockerfile:161 (COPY .ci/scripts/retry.sh /usr/local/bin/retry) and :164 (RUN retry git clone https://github.com/abseil/abseil-cpp.git ...); plus the ucx_custom_image stage in the CI-container Dockerfile ([4/5] STEP 6/6, retry git submodule update --init), which has no such COPY. Helper: .ci/scripts/retry.sh:18-22.

Suggested fix:

  1. Make retry available in every stage that calls it. Either add COPY .ci/scripts/retry.sh /usr/local/bin/retry at the top of the ucx_custom_image stage (and any other stage that starts FROM something else), or drop the external helper and inline the loop, e.g.
    RUN for i in 1 2 3 4 5; do git submodule update --init && break; [ $i -lt 5 ] && sleep $((i*15)); done
    A cheap guard is to add RUN command -v retry right after each COPY so a missing helper fails loudly at a trivial step instead of 30 minutes into the build.
  2. Harden the helper so a credential prompt can never stall or mask the real error: export GIT_TERMINAL_PROMPT=0 (and GIT_ASKPASS=/bin/true) in retry.sh, and echo the attempt number/exit code so retried failures are distinguishable in the log.
  3. For the abseil/gRPC/etc. clones, prefer the same pattern already used for UCX (clone on the CI host and COPY --from=) or point them at the internal mirror instead of unauthenticated https://github.com; retries alone will not survive a sustained GitHub refusal like the one in this build. Re-run once GitHub egress is confirmed healthy to validate the rest of the pipeline.

Related: PR #2291 (this change) — #2291

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id cf44c2f2-46d4-4dfd-9c69-8325a54d14bd in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-dl-gpu-ep · commit 8e74f598

TL;DR: The nixl-ci-dl-gpu-ep Docker build failed because .ci/patches/nixl_ep_vllm_release_test.patch no longer applies to vLLM — the Dockerfile resolves VLLM_REF to whatever the latest vLLM GitHub release is (now v0.30.0), and upstream changed tests/distributed/test_elastic_ep.py. Pin VLLM_REF to a known-good tag (PR #2292 already does this) and/or refresh the patch.

Full analysis

Summary: Stage "Build Docker" (node 63) failed at the BUILD_VLLM_ELASTIC_TEST layer: git apply of the vLLM elastic-EP test patch rejected.

Root cause: The Dockerfile step leaves VLLM_REF unset and resolves it at build time from api.github.com/repos/vllm-project/vllm/releases/latest. This build picked up Using vLLM release v0.30.0 (commit [REDACTED:Hex High Entropy String]). The in-repo patch expects the older layout of tests/distributed/test_elastic_ep.py around lines 175 and 204, and vLLM v0.30.0 changed that file, so:

error: patch failed: tests/distributed/test_elastic_ep.py:175
error: tests/distributed/test_elastic_ep.py: patch does not apply
subprocess exited with status 1
Error: building at STEP "RUN if [ "${BUILD_VLLM_ELASTIC_TEST}" = "true" ]; ..." : exit status 1

Everything before this (Mooncake, azure-sdk-for-cpp, gtest-parallel, azure-cli) built and installed cleanly, and the log shows continuous activity with no stalls — this is a hard failure, not a timeout or an infra problem. It is also unrelated to the PR under test (#2291, ci-github-clone-retry, which only touches git-clone retry logic); the build is floating on an external dependency, so it breaks for every branch as soon as vLLM cuts a release.

Implicated commit: c984ce65 — lishapira, "CI: add vLLM + NIXL EP test to the EP CI job (#2154)" — introduced both the patch and the unpinned "latest release" lookup. The immediate trigger is external: the vLLM v0.30.0 release.

File: .ci/patches/nixl_ep_vllm_release_test.patch:4 (hunk header @@ -175,6 +175,9 @@), applied by the BUILD_VLLM_ELASTIC_TEST RUN step in the EP Dockerfile under .ci/dockerfiles/.

Suggested fix:

  1. Pin the vLLM release instead of querying releases/latest — set a concrete ARG VLLM_REF=v0.2x.y default (the last tag the patch was validated against). This is exactly what PR CI: pin the vLLM release for the elastic EP test #2292 does; land it.
  2. Regenerate the patch against the pinned tag, and prefer git apply --3way so small upstream drift degrades to a merge attempt rather than a hard reject.
  3. Longer term, drop the patch: both hunks only add env-var overrides (VLLM_TEST_ELASTIC_EP_ALL2ALL_BACKEND, VLLM_ATTENTION_BACKEND). Upstreaming them to vLLM, or passing the flags via the test invocation/CLI args instead of patching the test file, removes this recurring breakage entirely.
  4. Add a guard so the resolved VLLM_REF is echoed and the patch failure is reported as a clear "patch needs refresh for " message rather than a bare exit status 1.

Related: PR #2292 — CI: pin the vLLM release for the elastic EP test (direct fix); PR #2154 — CI: add vLLM + NIXL EP test to the EP CI job (origin of the patch)

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id ba516c00-3774-42b9-9657-0d4347f35679 in the triage console for the audit trail.

The container and test builds fetch about 250 repositories anonymously
from github.com per PR run. During busy hours a small fraction of those
requests is refused (git reports "could not read Username"), which since
mid-September failed roughly 60% of nixl-ci-build-container-pr runs and a
third of nixl-ci-non-gpu runs. Two levers, both without changing what gets
built:

- Retry every git fetch up to 5 times with growing backoff (helper script
  in the images, shell function in build.sh, inline loop for the host-side
  ucx-src clone), pre-fetch the wrap-git meson subprojects the same way, and
  run the UCX submodule init under retry before autogen.sh, whose own
  gpunetio fetch failure is swallowed and only surfaces later in make.
- Initialize only the gRPC submodules this cmake configuration consumes:
  protobuf, c-ares, re2 and the xds proto set. SSL, Abseil and zlib come
  from the prefix, tests and the OpenTelemetry plugin are off, so their
  submodules (including opentelemetry-cpp's nested tree) were fetched for
  nothing. aws-sdk-cpp keeps its full CRT tree, but through a retried
  submodule init instead of --recurse-submodules.
@Alexey-Rivkin

Copy link
Copy Markdown
Contributor Author

/build

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-dl-gpu · commit 8e74f598

TL;DR: The DL GPU image build died at exit status 127 because the new retry() helper in .gitlab/build.sh resolves retry.sh through a relative $(dirname "$0"), which breaks as soon as the script cds into $BUILD_TMP; resolve the script directory to an absolute path once at the top.

Full analysis

Summary: Stage "Compiling NIXL Docker Image for DL" (build #2419) failed at STEP 16/18 of .ci/dockerfiles/Dockerfile.gpu-test: .gitlab/build.sh: line 25: .gitlab/../.ci/scripts/retry.sh: No such file or directory → podman exit status 127.

Root cause: Commit 8e74f59 added
retry() { "$(dirname "$0")/../.ci/scripts/retry.sh" "$@"; } (.gitlab/build.sh:25).
The Dockerfile invokes the script with a relative path (.gitlab/build.sh ${NIXL_INSTALL_DIR}, Dockerfile.gpu-test:46), so $0 is .gitlab/build.sh and dirname "$0" is the relative .gitlab. That only resolves while the CWD is still /workspace/nixl — which is why the . "$(dirname "$0")/../.ci/scripts/common.sh" on line 18 worked (it printed nixl_concurrent_id=26). Every retry call, however, runs inside a subshell that has already done cd ${BUILD_TMP}; the log shows exactly that sequence:

+ cd /tmp/tmp.q6djP3KvwN
+ retry git clone https://github.com/uccl-project/uccl.git
+ .gitlab/../.ci/scripts/retry.sh git clone https://github.com/uccl-project/uccl.git
.gitlab/build.sh: line 25: .gitlab/../.ci/scripts/retry.sh: No such file or directory

From /tmp/tmp.q6djP3KvwN there is no .gitlab/, so the helper is unfindable (127). .ci/scripts/retry.sh does exist in the repo and is in the build context — this is purely a path-resolution bug, not a missing file. The first retry reached here is the UCCL clone (build.sh:403, guarded by HAS_GPU && test -d $CUDA_HOME), which is why the GPU/DL job trips it while non-GPU or PRE_INSTALLED_* paths can slip past.

Implicated commit: [REDACTED:Hex High Entropy String] — Alexey Rivkin, "CI: retry git fetches and trim gRPC submodules in dependency builds"

File: .gitlab/build.sh:25 (failure triggered at .gitlab/build.sh:403; invoked from .ci/dockerfiles/Dockerfile.gpu-test:46)

Suggested fix: Resolve the script directory to an absolute path once, before any cd, and use it in the helper:

SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
. "${SCRIPT_DIR}/../.ci/scripts/common.sh"
retry() { "${SCRIPT_DIR}/../.ci/scripts/retry.sh" "$@"; }

SCRIPT_DIR is exported/inherited into the ( cd ${BUILD_TMP} && ... ) subshells, so all ~12 retry call sites then work. Also worth adding a fail-fast guard ([ -x "${SCRIPT_DIR}/../.ci/scripts/retry.sh" ] || { echo "retry.sh missing" >&2; exit 1; }) so a future packaging slip fails with a clear message instead of a bare 127, and verify retry.sh is committed with the executable bit set.

Related: #2291

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 1d1a5906-6a2a-4b0b-a30d-03574dc22e26 in the triage console for the audit trail.

@svc-nixl

Copy link
Copy Markdown
Collaborator

🤖 CI Triage Agent — nixl-ci-dl-gpu-ep · commit 9dee74d6

TL;DR: The "Build Docker" stage failed because git apply /tmp/nixl_ep_vllm_release_test.patch could not apply to tests/distributed/test_elastic_ep.py in the latest vLLM release (v0.30.0), which the Dockerfile resolves dynamically at build time; pin VLLM_REF to a known-good tag (or refresh the patch).

Full analysis

Summary: nixl-ci-dl-gpu-ep #1335 failed in stage 57 ("Build Docker") at the BUILD_VLLM_ELASTIC_TEST image step — git apply of the elastic-EP test patch rejected, aborting the container build with exit status 1.

Root cause: Not a code defect in the PR under test (ci-github-clone-retry, PR #2291) and not a timeout — the build log shows continuous activity and a hard error. The Dockerfile step resolves the vLLM revision at build time when VLLM_REF is empty:

VLLM_REF="$(python3 -c '... api.github.com/repos/vllm-project/vllm/releases/latest ... ["tag_name"]')"

The log shows it picked up Using vLLM release v0.30.0, cloned it, then:

error: patch failed: tests/distributed/test_elastic_ep.py:175
error: tests/distributed/test_elastic_ep.py: patch does not apply
subprocess exited with status 1
Error: building at STEP "RUN if [ "${BUILD_VLLM_ELASTIC_TEST}" = "true" ]; then ... git -C "${VLLM_ELASTIC_TEST_DIR}" apply /tmp/nixl_ep_vllm_release_test.patch && ..."

Because the reference floats to whatever vLLM tagged most recently, upstream edits around tests/distributed/test_elastic_ep.py:175 in v0.30.0 invalidated the vendored context lines in nixl_ep_vllm_release_test.patch. This is an unpinned-external-dependency failure: the same image build would have succeeded before vLLM cut v0.30.0, with no nixl change involved. It will keep failing for every branch/PR until the pin or the patch is updated.

Implicated commit: No nixl commit broke this — the trigger is upstream vLLM's v0.30.0 release. The fragile mechanism was introduced in c984ce65 (lishapira, "CI: add vLLM + NIXL EP test to the EP CI job", #2154), which added the patch and the releases/latest lookup.

File: The RUN step guarded by BUILD_VLLM_ELASTIC_TEST in the EP CI Dockerfile under .ci/dockerfiles/ (the VLLM_REF fallback that queries releases/latest), plus the patch nixl_ep_vllm_release_test.patch copied to /tmp/nixl_ep_vllm_release_test.patch; the rejected hunk targets vLLM tests/distributed/test_elastic_ep.py:175.

Suggested fix: Pin VLLM_REF to the last known-good vLLM tag (e.g. the release the patch was authored against) instead of resolving releases/latest at build time — this is exactly what PR #2292 does, so land/rebase onto that. Then, as a follow-up, regenerate nixl_ep_vllm_release_test.patch against v0.30.0 and bump the pin deliberately. Two hardening suggestions: (1) make the git apply failure loud and actionable by adding --3way or a preceding git apply --check with an explicit "patch needs refresh for ${VLLM_REF}" message; (2) since this test is an optional add-on, consider not failing the whole image build on it, or better, keep it hard-failing but pinned so breakage only happens when someone intentionally bumps the version. Note PR #2291's own changes (git clone retries) are unrelated and were working here — the retry git clone wrappers for gtest-parallel and azure-sdk-for-cpp both succeeded in this log.

Related: #2292 (CI: pin the vLLM release for the elastic EP test — the direct fix); #2154 (introduced the patch + floating releases/latest lookup); #2291 (PR under test, unrelated to this failure)

NirWolfer added a commit that referenced this pull request Oct 7, 2026
Makes `.gitlab/build.sh` fail at the Mooncake clone, with git's error,
when that clone fails. Today the build carries on and fails later with a
misleading exit 127.

The `sed -i '/liburing-dev/d' dependencies.sh` line in the Mooncake
block has no trailing `&& \`, so the subshell is split into two `&&`
lists. `set -e` does not fire on a failure inside a list. A failed clone
therefore falls through to `bash dependencies.sh` in `${BUILD_TMP}`,
which fails with `No such file or directory` and exit 127. This happened
in nixl-ci-gpu #3885, where the clone failed with `curl 56 Recv failure:
Connection reset by peer`.

Running the block on its own with `git` stubbed out confirms it: a
failed clone exits 127 before the change and exits 128 at the clone
after it. A successful clone behaves the same in both cases.

Changes:

- `.gitlab/build.sh` — add the missing `&& \` after the `sed` line in
the Mooncake block.

#2291 adds `retry` to this same clone, so this PR doesn't add a retry.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* The build now proceeds to subsequent steps only when dependency
installation succeeds. If installation fails, later steps are skipped,
helping ensure the reported build result reflects whether its required
dependencies were installed successfully. This change affects the build
process and does not alter end-user features or application behavior.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: NirWolfer <nwolfer@nvidia.com>
svc-nixl referenced this pull request Oct 7, 2026
Select EP proxy mode through backend parameters while retaining direct mode
as the default. Derive topology from EP rank capacity and proxy settings,
erase the inherited num_workers default, and disable shared background
progress because the proxy owns its progress threads.

Signed-off-by: Tomer Davidor <tdavidor@nvidia.com>
svc-nixl referenced this pull request Oct 9, 2026
## What?
Two follow-ups to #2241 (generic S3-over-RDMA in the OBJ plugin): 
1. Keep cuObject/RDMA headers out of `s3_accel/client.h` to fix a
wheel-build OOM.
2. Review cleanups that came in after #2241 merged. 

## Why? 
- `s3_accel/client.h` included `object/rdma/rdma.h`, so every file
including it compiled the full cuObject header set. That pushed compiler
memory high enough to OOM the wheel build.
- Review cleanups: 
- The cuObject accelerated tests skipped on any construction failure,
which hid real errors.

## How?
- `client.h` forward-declares the RDMA types; `rdma.h` is included only
in the `.cpp` files that need it.
- Empty accel `type` → `"s3"` is now resolved in the engine registry
instead of `createAccelEngine`.
- cuObject accelerated tests skip when `NIXL_OBJ_ENDPOINT_OVERRIDE` is
unset (like the Dell tests) and only skip a construction failure when
the fast path is unavailable; anything else fails.
 - `const nixl_b_params_t *` on the param getters, plus comment fixes.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Object acceleration requests without an explicitly specified engine
now use the S3 engine when available. If it is unavailable, the request
reports that no engine type was specified.

* **Bug Fixes**
* Zero-byte RDMA writes are now treated as successful, preventing
unnecessary retries.
* Accelerated-object tests now skip when the endpoint is unset or the
fast path is unavailable, while reporting other engine construction
failures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Adit Ranadive <aranadive@nvidia.com>
svc-nixl referenced this pull request Oct 13, 2026
Nothing verified the closed-source `ucx-spcx-plugin` still compiles when
its ref or the UCX under it moved — that only surfaced in the nightly.
Building it in the per-PR wheel job was not an option: this repo is
public, everything in a PR's checkout is editable by whoever opened the
PR, and that job's console can be published back to the PR, so cloning
the plugin here would hand its read credential and its source to
PR-authored code.

`nixl-ci-build-wheel` now triggers `nixl-ci-compile-ucx-plugin` from
`pipeline_start` and fails the job if it fails, before any wheel is
built. That job's definition, matrix and build scripts live in the
plugin repo (`ucx-spcx-plugin!45`), so a PR can choose which ref to
build but cannot change what the job does; it runs on the NIXL Jenkins
only so it can stage the built module on the shared PVC. Both arches
build in one run, and only the module and a pass/fail cross back.

- `build-wheel-matrix.yaml`: `pipeline_start` triggers the compile job
and errors on failure; adds `UCX_SPCX_PLUGIN_REF` and
`SPCX_STAGING_ROOT`; Build Wheel passes `--ucx-spcx-plugin-install`
- `build-container.sh`: new `--ucx-spcx-plugin-install <dir>` stages a
pre-built module into the build context, needing no gitlab credentials
- `Dockerfile.manylinux`: installs the staged module when present,
otherwise keeps compiling from staged source —
`nixl-ci-build-wheel-nightly` does a full two-stage build and has no
published `wheel_base` to compile against yet
- `.gitignore`, `.ci/docs/ci-overview.md`,
`.ci/docs/build-wheel-matrix-ci.md` updated

Blocked on `ucx-spcx-plugin!45` merging to `v0.3.x` and DevOps applying
`proj_jjb_nixl.yaml` to the NIXL Jenkins. The top commit pins the plugin
ref to the MR branch so the flow can be exercised before then, and must
be reverted before merge.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Wheel and container builds can install pre-built UCX SPCX plugin
modules.
- Nightly CUDA 12 and 13 wheel builds use reusable,
architecture-specific base images.

- **Bug Fixes**
- Builds now fail when plugin compilation fails or required staged
plugin files are missing.
  - Plugin staging directories are validated before use.

- **Documentation**
- Updated CI guidance to describe plugin workflows, sourcing, and
security boundaries.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: NirWolfer <nwolfer@nvidia.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
svc-nixl referenced this pull request Oct 13, 2026
…ms (#2386)

When the AWS EFA Batch job fails, the wrapper prints only `Job reached
terminal status FAILED after <N>s`. That makes a timeout, a lost node
and a real test failure look the same.

Three AWS failures on 2026-10-07 show the problem:

- PR #2211: etcd received SIGTERM at 19:34:45.97, exactly 60 minutes
after `timeout 60m bash contrib/aws-efa/aws_test_remote.sh` started at
18:34:46.03. GNU `timeout` signals the whole process group, so this was
the in-pod `TEST_TIMEOUT`, not an external kill.
- PR #2328: `kubectl logs -f` ended with `http2: server sent GOAWAY`,
and the `--previous` fallback failed with `previous terminated container
"default" ... not found` because the container was still running. The
job went FAILED 60 minutes 11 seconds after `timeout 60m` started, so
this was also the in-pod timeout. Both runs were slowed by that
evening's apt slowdown (build about 53 minutes, against about 22
normally).
- PR #2359: the log ended cleanly 7 minutes into the gRPC build, and
Batch marked the job FAILED 13 minutes later. The cause is not in the
log.

In the AWS run logs I sampled, the GOAWAY drop hit 4 of about 67 runs,
three of them otherwise successful. The `--previous` fallback never
recovered any output.

Changes:

- `contrib/aws-efa/aws_test.sh`: a new `report_job_failure` runs when
the job fails to start or does not reach `SUCCEEDED`. It prints the
Batch `statusReason` and, for each attempt (`eksAttempts`), the pod,
node, status reason and each container's exit code and reason. If an
exit code is 124, it prints that the in-pod test timeout expired.
- `contrib/aws-efa/aws_test.sh`: a new `follow_pod_logs` replaces
`kubectl logs -f || kubectl logs --previous`. It follows the log with
`--timestamps` and prints each line without its timestamp. If the stream
ends while the container is still running, it reconnects with
`--since-time` set to the last line received, up to 10 times. kubelet
applies `--since-time` with 1 s granularity and prints timestamps at a
fixed nanosecond width, so lines up to the last one received are skipped
by comparing timestamps.
- `contrib/aws-efa/README.md`: describe both behaviours in the execution
flow.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Improvements**
* AWS test runs now stream timestamped pod logs and retry up to 10 times
if the stream drops while a container is running, resuming after the
last received timestamp without repeating lines.
* Failure reports now include AWS Batch status and status reason, plus
each attempt’s pod, node, and container exit details. When
`TEST_TIMEOUT` is set and a container exits with code 124, reports
identify an in-pod timeout.
* **Documentation**
* Updated test execution guidance to describe log reconnections and the
additional failure details.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: NirWolfer <nwolfer@nvidia.com>

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants