[CI] Build the Rust extensions on the 5090 pool and seed the cache from main (#33460)
This commit is contained in:
@@ -150,8 +150,17 @@ jobs:
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
export PATH="${CARGO_HOME:-$HOME/.cargo}/bin:${PATH}"
|
||||
# Same path ci_install_dependency.sh uses: one warm cargo cache per host.
|
||||
# Same path ci_install_dependency.sh uses, so a runner that also runs test
|
||||
# stages keeps one warm cache. Its guard is repeated here because nothing
|
||||
# prunes the tree on a runner that only ever builds.
|
||||
export CARGO_TARGET_DIR="${HOME}/.cache/sglang-cargo-target"
|
||||
mkdir -p "${CARGO_TARGET_DIR}"
|
||||
used="$(df --output=pcent "${CARGO_TARGET_DIR}" 2>/dev/null | tr -dc '0-9')"
|
||||
if [ "${used:-0}" -ge 85 ]; then
|
||||
echo "cargo target dir filesystem at ${used}%; dropping ${CARGO_TARGET_DIR}"
|
||||
rm -rf "${CARGO_TARGET_DIR}"
|
||||
mkdir -p "${CARGO_TARGET_DIR}"
|
||||
fi
|
||||
python3 -m pip install --upgrade pip
|
||||
command -v uv >/dev/null 2>&1 || pip install uv
|
||||
# build_rust needs only the build backend, not sglang's ~294 runtime deps.
|
||||
@@ -167,6 +176,22 @@ jobs:
|
||||
MAX_GLIBC: ${{ inputs.max_glibc }}
|
||||
run: bash scripts/ci/utils/stage_rust_ext_modules.sh
|
||||
|
||||
# actions/cache identifies an entry by key *and* a version derived from the
|
||||
# compression tool, so a runner without zstd saves what the hosted restore job
|
||||
# cannot find - a silent miss every run. Warn, not fail: a cold build still works.
|
||||
- name: Ensure zstd so the restore job can read what this job saves
|
||||
run: |
|
||||
set -uo pipefail
|
||||
if ! command -v zstd >/dev/null 2>&1; then
|
||||
if [ "$(id -u)" = "0" ]; then SUDO=""
|
||||
elif command -v sudo >/dev/null 2>&1; then SUDO="sudo"
|
||||
else SUDO=""; fi
|
||||
${SUDO} apt-get update || true
|
||||
${SUDO} apt-get install -y --no-install-recommends zstd || true
|
||||
fi
|
||||
command -v zstd >/dev/null 2>&1 \
|
||||
|| echo "::warning::zstd unavailable on ${RUNNER_NAME:-this runner}; the cache entry saved below will not be readable by the restore job"
|
||||
|
||||
# After the verify step, so a rejected build cannot poison this key for every
|
||||
# later run.
|
||||
- name: Save built modules
|
||||
|
||||
@@ -144,7 +144,7 @@ jobs:
|
||||
(needs.call-gate.result == 'success' || needs.call-gate.result == 'skipped')
|
||||
uses: ./.github/workflows/_pr-test-rust-ext-build.yml
|
||||
with:
|
||||
runs_on: x64-kernel-build-node
|
||||
runs_on: 1-gpu-5090
|
||||
artifact_name: rust-ext-x86_64-extra
|
||||
git_ref: ${{ inputs.git_ref || '' }}
|
||||
skip_pr_test_health_check: ${{ inputs.skip_pr_test_health_check == true }}
|
||||
|
||||
@@ -226,7 +226,7 @@ jobs:
|
||||
(needs.call-gate.result == 'success' || needs.call-gate.result == 'skipped')
|
||||
uses: ./.github/workflows/_pr-test-rust-ext-build.yml
|
||||
with:
|
||||
runs_on: x64-kernel-build-node
|
||||
runs_on: 1-gpu-5090
|
||||
git_ref: ${{ inputs.git_ref || '' }}
|
||||
skip_pr_test_health_check: ${{ inputs.skip_pr_test_health_check == true }}
|
||||
secrets: inherit
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
name: Seed Rust Ext Cache
|
||||
|
||||
# A cache entry only reaches every PR when it was written from the default branch's
|
||||
# ref, and pr-test.yml has no push trigger - so a merge that moves the key leaves
|
||||
# every PR compiling for itself until the next scheduled run, up to 12h later.
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'rust/**'
|
||||
- 'python/setup.py'
|
||||
workflow_dispatch:
|
||||
|
||||
# Only the newest merge needs to seed; earlier ones are already stale.
|
||||
concurrency:
|
||||
group: seed-rust-ext-cache
|
||||
cancel-in-progress: true
|
||||
|
||||
# Declaring permissions at all drops everything not listed, and check-maintenance
|
||||
# needs issues: read to reach the maintenance issue.
|
||||
permissions:
|
||||
contents: read
|
||||
issues: read
|
||||
|
||||
jobs:
|
||||
seed:
|
||||
uses: ./.github/workflows/_pr-test-rust-ext-build.yml
|
||||
with:
|
||||
runs_on: 1-gpu-5090
|
||||
secrets: inherit
|
||||
@@ -16,7 +16,6 @@ use crate::error::Error;
|
||||
|
||||
// `Failed(Error)` carries the cause for observability even where it isn't read
|
||||
// back yet; `EncodeDone` belongs to the deferred Encoder edge.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RequestState {
|
||||
Received,
|
||||
|
||||
@@ -263,7 +263,6 @@ fn cache_bound(pattern: &str, max_len: usize) {
|
||||
/// can pair one pattern's bound with another's, and there is no second route to a
|
||||
/// bound that could drift from the validated one.
|
||||
pub struct RegexPattern<'a> {
|
||||
#[allow(dead_code)]
|
||||
pattern: &'a str,
|
||||
max_len: usize,
|
||||
}
|
||||
@@ -310,7 +309,6 @@ impl<'a> RegexPattern<'a> {
|
||||
Ok(Self { pattern, max_len })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// The admitted pattern. See the field note on why this is kept.
|
||||
#[allow(dead_code)]
|
||||
pub fn pattern(&self) -> &str {
|
||||
|
||||
@@ -673,6 +673,19 @@ if spec.origin != want:
|
||||
print(f"sglang resolves to {spec.origin}")
|
||||
'
|
||||
|
||||
# Import, not find_spec: the finders locate an extension without dlopening it,
|
||||
# so a .so that cannot load passes find_spec and only fails inside some suite.
|
||||
python3 -c '
|
||||
import importlib
|
||||
for mod in ("server", "grpc", "multimodal"):
|
||||
name = f"sglang.srt.{mod}._core"
|
||||
try:
|
||||
importlib.import_module(name)
|
||||
except Exception as exc:
|
||||
raise SystemExit(f"{name} is present but does not load: {exc!r}")
|
||||
print(f"{name} loads")
|
||||
'
|
||||
|
||||
mark_step_done "${FUNCNAME[0]}"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user