mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-11 06:28:58 +00:00
* feat(ci): split backend unit tests into parallel CI shards Split the single offline backend `make test` job into four GitHub Actions matrix shards (SPLITS=4, GROUP=1..4) via pytest-split, so the ~12k-test suite runs in parallel instead of in one 15-minute job. Each shard runs on its own runner with its own Postgres/Redis services; fail-fast: false lets a failing shard report its owned tests without cancelling its peers. `make test` stays the canonical full-suite entry point; CI now calls the new `make test-shard SPLITS=4 GROUP=N`. tests/blocking_io remains owned solely by the dedicated blocking-I/O workflow (excluded via --ignore), extending #5105. Fixes #5088 * test(ci): make backend test shards duration-aware and pin the contract Make `make test-shard` an explicit least_duration split that READS backend/.test_durations (read-only for shards, so concurrent CI jobs never race writes on it), and add `make test-shard-durations` to regenerate that file from the full offline suite. Update the CI unit-test workflow contract to call `make test-shard SPLITS=4 GROUP=<n>` and assert the shard command carries --splits 4, --group 2, -m "not live", --ignore=tests/blocking_io and --splitting-algorithm least_duration. Verified on the real 13,140-test normal suite that the four shards are pairwise disjoint and their union equals the unsplit suite. Refs #5088 * test(ci): fail fast when the duration baseline is missing `make test-shard` now requires backend/.test_durations and exits with a clear error instead of letting pytest-split silently degrade to an even (count-based) split. Harden the CI contract test to pin `--durations-path=.test_durations` and to assert the repo ships the committed duration baseline. Refs #5088 * docs: trim backend/AGENTS.md within guidance budget * test(ci): add backend test duration baseline Add the duration baseline generated by a full offline backend run on a GitHub-hosted ubuntu-latest runner (the same runner type the shards use), so `make test-shard` balances the four matrix shards by real wall-clock cost. Refs #5088 * test(ci): make the duration writer honor DURATIONS_FILE `test-shard-durations` now writes `--durations-path=$(DURATIONS_FILE)` instead of a hard-coded .test_durations, so the reader and writer stay consistent when the path is overridden. Refs #5088 * test(ci): address sharding review feedback * test: isolate subagent execution capacity state --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
73 lines
3.5 KiB
Makefile
73 lines
3.5 KiB
Makefile
DEER_FLOW_HOME ?= $(CURDIR)/.deer-flow
|
|
DEER_FLOW_HOME := $(abspath $(DEER_FLOW_HOME))
|
|
BACKEND_SANDBOX_HOME := $(abspath $(CURDIR)/sandbox)
|
|
|
|
install:
|
|
uv sync --locked
|
|
|
|
dev:
|
|
mkdir -p "$(DEER_FLOW_HOME)" "$(BACKEND_SANDBOX_HOME)"
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 DEER_FLOW_HOME="$(DEER_FLOW_HOME)" uv run --locked uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001 \
|
|
--reload \
|
|
--reload-include='*.yaml' \
|
|
--reload-include='.env' \
|
|
--reload-exclude='*.pyc' \
|
|
--reload-exclude='__pycache__' \
|
|
--reload-exclude="$(BACKEND_SANDBOX_HOME)" \
|
|
--reload-exclude="$(DEER_FLOW_HOME)"
|
|
|
|
gateway:
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run --locked uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001
|
|
|
|
test:
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run pytest -m "not live" --ignore=tests/blocking_io tests/ -v
|
|
|
|
test-live:
|
|
DEER_FLOW_RUN_LIVE_TESTS=1 PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run pytest -m live tests/ -v -s
|
|
|
|
test-blocking-io:
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run pytest tests/blocking_io -q --tb=short
|
|
|
|
# Run the backend unit-test suite as one shard of a parallel CI split.
|
|
# SPLITS = total number of shards; GROUP = 1-based shard index.
|
|
# Duration-aware: `least_duration` balances the shards by real wall-clock cost
|
|
# read from .test_durations. Shards only READ that file (no --store-durations),
|
|
# so concurrent CI jobs cannot race writes on it. Refresh it with
|
|
# `make test-shard-durations` after a meaningful change to the test set.
|
|
# `make test-shard SPLITS=4 GROUP=2` runs shard 2 of 4; a bare `make test-shard`
|
|
# runs the whole (non-live) suite as a single split, matching `make test`.
|
|
SPLITS ?= 1
|
|
GROUP ?= 1
|
|
DURATIONS_FILE ?= .test_durations
|
|
test-shard:
|
|
@test -f "$(DURATIONS_FILE)" || \
|
|
(echo "error: $(DURATIONS_FILE) is missing; run 'make test-shard-durations' to regenerate the duration baseline" >&2; exit 1)
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run pytest -m "not live" --ignore=tests/blocking_io --splits $(SPLITS) --group $(GROUP) --splitting-algorithm least_duration --durations-path=$(DURATIONS_FILE) tests/ -q
|
|
|
|
# Regenerate .test_durations from the full offline (non-live, non-blocking-I/O)
|
|
# suite so duration-aware sharding reflects real wall-clock cost. Run locally or
|
|
# in a periodic job, then commit the refreshed file.
|
|
test-shard-durations:
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run pytest -m "not live" --ignore=tests/blocking_io --store-durations --clean-durations --durations-path=$(DURATIONS_FILE) tests/ -q
|
|
|
|
lint:
|
|
uv run ruff check .
|
|
uv run ruff format --check .
|
|
|
|
format:
|
|
uv run ruff check . --fix && uv run ruff format .
|
|
|
|
detect-blocking-io:
|
|
@PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run python ../scripts/detect_blocking_io_static.py --output ../.deer-flow/blocking-io-findings.json
|
|
|
|
# Generate a new alembic revision by autogenerating the diff against the live
|
|
# ORM models. Usage: make migrate-rev MSG="add foo column to runs"
|
|
# The Gateway runs `alembic upgrade head` automatically at startup via
|
|
# `bootstrap_schema`, so there is intentionally no `migrate` / `migrate-stamp`
|
|
# target -- the single execution path keeps ops mistakes off the table.
|
|
# The script builds a fresh temp SQLite at head, then diffs the live models
|
|
# against it, so a clean checkout does NOT need a pre-existing ./data/deerflow.db.
|
|
migrate-rev:
|
|
@if [ -z "$(MSG)" ]; then echo 'usage: make migrate-rev MSG="describe the change"'; exit 1; fi
|
|
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run python scripts/_autogen_revision.py "$(MSG)"
|