diff --git a/.github/workflows/_pr-test-rust-ext-build.yml b/.github/workflows/_pr-test-rust-ext-build.yml index 5d832d947..2978ffe3f 100644 --- a/.github/workflows/_pr-test-rust-ext-build.yml +++ b/.github/workflows/_pr-test-rust-ext-build.yml @@ -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 diff --git a/.github/workflows/pr-test-extra.yml b/.github/workflows/pr-test-extra.yml index 944d1f236..3155c77e3 100644 --- a/.github/workflows/pr-test-extra.yml +++ b/.github/workflows/pr-test-extra.yml @@ -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 }} diff --git a/.github/workflows/pr-test.yml b/.github/workflows/pr-test.yml index 9fa12327d..40823cf28 100644 --- a/.github/workflows/pr-test.yml +++ b/.github/workflows/pr-test.yml @@ -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 diff --git a/.github/workflows/seed-rust-ext-cache.yml b/.github/workflows/seed-rust-ext-cache.yml new file mode 100644 index 000000000..2aa698120 --- /dev/null +++ b/.github/workflows/seed-rust-ext-cache.yml @@ -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 diff --git a/rust/sglang-server/src/fsm.rs b/rust/sglang-server/src/fsm.rs index afb1f58a7..2e54f7b6a 100644 --- a/rust/sglang-server/src/fsm.rs +++ b/rust/sglang-server/src/fsm.rs @@ -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, diff --git a/rust/sglang-server/src/utils/regex.rs b/rust/sglang-server/src/utils/regex.rs index 65e57abc3..92106b0a7 100644 --- a/rust/sglang-server/src/utils/regex.rs +++ b/rust/sglang-server/src/utils/regex.rs @@ -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 { diff --git a/scripts/ci/cuda/ci_install_dependency.sh b/scripts/ci/cuda/ci_install_dependency.sh index 4d02d1d3d..5c1870fff 100755 --- a/scripts/ci/cuda/ci_install_dependency.sh +++ b/scripts/ci/cuda/ci_install_dependency.sh @@ -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]}" }