fix(serve): resource governor for multi-instance system freezes #385
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| lint: | |
| # Static analysis gate — fails the PR if ruff finds any issues. Runs on | |
| # a single Python version (lint output is OS/version-independent) so it's | |
| # cheap and finishes well before the test matrix. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install ruff | |
| run: pip install "ruff>=0.13" | |
| - name: Ruff check | |
| run: ruff check src/ tests/ | |
| test: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install system dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update && sudo apt-get install -y cmake | |
| - name: Install system dependencies (Windows) | |
| if: runner.os == 'Windows' | |
| run: choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' -y | |
| # macOS setup-python ships Python without loadable SQLite extensions. | |
| # Build pysqlite3 from source against Homebrew SQLite (which has | |
| # extensions enabled), then patch sys.modules so `import sqlite3` | |
| # uses the extension-capable build. | |
| - name: Fix SQLite extensions (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| brew install sqlite3 | |
| LDFLAGS="-L$(brew --prefix sqlite3)/lib" \ | |
| CPPFLAGS="-I$(brew --prefix sqlite3)/include" \ | |
| pip install pysqlite3 | |
| SITE=$(python -c "import site; print(site.getsitepackages()[0])") | |
| cat > "$SITE/patch_sqlite3.pth" << 'PATCH' | |
| import pysqlite3; import sys; sys.modules["sqlite3"] = pysqlite3; sys.modules["sqlite3.dbapi2"] = pysqlite3 | |
| PATCH | |
| python -c "import sqlite3; c = sqlite3.connect(':memory:'); c.enable_load_extension(True); print('SQLite extensions: OK')" | |
| - name: Install package | |
| # Test matrix needs the `local` extra so fastembed-backed tests in | |
| # tests/indexer/test_embedder.py and scripts/bench_recall.py still | |
| # exercise the real ONNX path. The core-only install path (without | |
| # fastembed) is covered separately by the `install-core-only` job. | |
| run: pip install -e ".[dev,local]" | |
| # Pin fastembed's cache for BOTH the warm step and the test step so | |
| # they share state. Embedder defaults to ~/.cache/fastembed under | |
| # #67, and fastembed itself honours FASTEMBED_CACHE_PATH — setting | |
| # this env var keeps the warm step and the tests pointed at the | |
| # same directory without needing explicit kwargs. | |
| - name: Warm fastembed model cache | |
| env: | |
| FASTEMBED_CACHE_PATH: ${{ runner.temp }}/fastembed-cache | |
| run: | | |
| python -c "from fastembed import TextEmbedding; TextEmbedding('BAAI/bge-small-en-v1.5')" | |
| python -c "from fastembed import TextEmbedding; TextEmbedding('sentence-transformers/all-MiniLM-L6-v2')" | |
| - name: Run tests | |
| shell: bash | |
| env: | |
| FASTEMBED_CACHE_PATH: ${{ runner.temp }}/fastembed-cache | |
| # Windows GitHub Actions runners send spurious SIGINT during pytest | |
| # teardown, causing exit code 1 even when all tests pass. Using | |
| # `shell: bash` ensures `|| true` is evaluated by bash on all | |
| # platforms. The follow-up XML parse step then enforces no actual | |
| # test cases failed. | |
| run: pytest -n ${{ runner.os == 'Windows' && '0' || '4' }} --cov=context_engine --cov-report=xml --cov-report=term --junitxml=junit-results.xml || ${{ runner.os == 'Windows' && 'true' || 'false' }} | |
| - name: Verify no test failures (Windows teardown workaround) | |
| if: runner.os == 'Windows' | |
| run: python -c "import xml.etree.ElementTree as ET; r=ET.parse('junit-results.xml').getroot(); f=int(r.get('failures','0'))+int(r.get('errors','0')); print(f'failures={f}'); exit(f)" | |
| - name: Upload coverage | |
| if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: coverage.xml | |
| install-core-only: | |
| # Regression guard for #62 — `pip install code-context-engine` without | |
| # the [local] extra must succeed on every supported OS/Python combo | |
| # without compiling Rust or requiring MSVC. fastembed is the heavy | |
| # transitive dep that historically blocked Windows + new Python | |
| # versions; this job ensures the core install never pulls it. | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install core (no extras) | |
| run: pip install -e . | |
| - name: Verify fastembed is NOT installed | |
| shell: bash | |
| run: | | |
| if python -c "import fastembed" 2>/dev/null; then | |
| echo "ERROR: fastembed leaked into the core install — it should be opt-in via [local]" | |
| exit 1 | |
| fi | |
| echo "Core install confirmed fastembed-free." | |
| - name: Verify package imports cleanly | |
| run: | | |
| python -c "import context_engine; print('OK', context_engine.__version__)" | |
| python -c "from context_engine.indexer.embedder import Embedder, OllamaBackend, select_backend; print('OK embedder module')" |