mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-09-09 21:49:37 +00:00
fix(dev): exclude backend runtime state from reload (#4759)
This commit is contained in:
parent
9ba04bf80c
commit
f78730ab86
@ -98,7 +98,7 @@ make stop # Stop all services
|
||||
**Backend directory** (for backend development only):
|
||||
```bash
|
||||
make install # Install backend dependencies
|
||||
make dev # Run Gateway API with reload (port 8001)
|
||||
make dev # Run Gateway API with runtime-safe reload (port 8001)
|
||||
make gateway # Run Gateway API only (port 8001)
|
||||
make test # Run offline backend tests (excludes live external-API tests)
|
||||
make test-live # Explicitly run live DeerFlowClient tests with real APIs
|
||||
@ -108,6 +108,12 @@ make format # Format code with ruff
|
||||
make migrate-rev MSG="..." # Autogenerate a new alembic revision (see Schema Migrations section)
|
||||
```
|
||||
|
||||
The backend `make dev` target pre-creates and excludes `DEER_FLOW_HOME`
|
||||
(default: `backend/.deer-flow`) and `backend/sandbox` from Uvicorn's reload
|
||||
watcher. Do not replace it with a bare `uvicorn --reload`: agent tasks write
|
||||
Python and other runtime files below `DEER_FLOW_HOME`, which would otherwise
|
||||
restart the Gateway during an active run.
|
||||
|
||||
The root `detect-thread-boundaries` target statically inventories execution
|
||||
boundaries under `backend/app/` and `backend/packages/harness/deerflow/`. It
|
||||
prints a concise count by execution domain and writes the complete, versioned
|
||||
|
||||
@ -1,8 +1,20 @@
|
||||
DEER_FLOW_HOME ?= $(CURDIR)/.deer-flow
|
||||
DEER_FLOW_HOME := $(abspath $(DEER_FLOW_HOME))
|
||||
BACKEND_SANDBOX_HOME := $(abspath $(CURDIR)/sandbox)
|
||||
|
||||
install:
|
||||
uv sync
|
||||
|
||||
dev:
|
||||
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 uv run uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001 --reload
|
||||
mkdir -p "$(DEER_FLOW_HOME)" "$(BACKEND_SANDBOX_HOME)"
|
||||
PYTHONPATH=. PYTHONIOENCODING=utf-8 PYTHONUTF8=1 DEER_FLOW_HOME="$(DEER_FLOW_HOME)" uv run 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 uvicorn app.gateway.app:app --host 0.0.0.0 --port 8001
|
||||
|
||||
@ -414,7 +414,7 @@ If a provider is explicitly enabled but required credentials are missing, or the
|
||||
|
||||
```bash
|
||||
make install # Install dependencies
|
||||
make dev # Run Gateway API + embedded agent runtime (port 8001)
|
||||
make dev # Run Gateway API + embedded agent runtime with safe reload (port 8001)
|
||||
make gateway # Run Gateway API without reload (port 8001)
|
||||
make lint # Run linter (ruff)
|
||||
make format # Format code (ruff)
|
||||
@ -422,6 +422,12 @@ make detect-blocking-io # Inventory blocking IO that may block the backend even
|
||||
make migrate-rev MSG="..." # Autogenerate a new alembic revision against the live ORM models
|
||||
```
|
||||
|
||||
`make dev` pre-creates and excludes `DEER_FLOW_HOME` (by default
|
||||
`backend/.deer-flow`) and `backend/sandbox` from Uvicorn's reload watcher. Use
|
||||
this target instead of a bare `uvicorn --reload`: agent tasks write Python and
|
||||
other runtime files under `DEER_FLOW_HOME`, and watching that directory can
|
||||
restart the Gateway during an active run.
|
||||
|
||||
### Schema Migrations
|
||||
|
||||
DeerFlow's application tables (`runs`, `threads_meta`, `feedback`, `users`,
|
||||
|
||||
@ -98,6 +98,18 @@ def test_local_dev_gateway_reload_excludes_runtime_state_with_absolute_dirs():
|
||||
assert "--reload-exclude='.deer-flow/'" not in serve_sh
|
||||
|
||||
|
||||
def test_backend_make_dev_gateway_reload_excludes_runtime_state_with_absolute_dirs():
|
||||
makefile = _read("backend/Makefile")
|
||||
|
||||
assert "DEER_FLOW_HOME ?= $(CURDIR)/.deer-flow" in makefile
|
||||
assert "DEER_FLOW_HOME := $(abspath $(DEER_FLOW_HOME))" in makefile
|
||||
assert "BACKEND_SANDBOX_HOME := $(abspath $(CURDIR)/sandbox)" in makefile
|
||||
assert 'mkdir -p "$(DEER_FLOW_HOME)" "$(BACKEND_SANDBOX_HOME)"' in makefile
|
||||
assert 'DEER_FLOW_HOME="$(DEER_FLOW_HOME)" uv run uvicorn' in makefile
|
||||
assert '--reload-exclude="$(DEER_FLOW_HOME)"' in makefile
|
||||
assert '--reload-exclude="$(BACKEND_SANDBOX_HOME)"' in makefile
|
||||
|
||||
|
||||
def test_backend_container_only_exposes_gateway_port():
|
||||
dockerfile = _read("backend/Dockerfile")
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ Two layers of coverage:
|
||||
* ``test_*_resolve_*`` exercises uvicorn's real ``resolve_reload_patterns`` to
|
||||
pin the failure mode and the fix's mechanism.
|
||||
* ``test_launcher_precreates_every_absolute_reload_exclude`` enforces the actual
|
||||
invariant on both launchers: every absolute exclude dir is ``mkdir -p``'d
|
||||
invariant on every dev launcher: every absolute exclude dir is ``mkdir -p``'d
|
||||
before uvicorn starts. This encodes the root cause, so any future absolute
|
||||
exclude that forgets its ``mkdir`` fails here.
|
||||
"""
|
||||
@ -35,6 +35,7 @@ REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
LAUNCHERS = {
|
||||
"scripts/serve.sh": REPO_ROOT / "scripts" / "serve.sh",
|
||||
"docker/dev-entrypoint.sh": REPO_ROOT / "docker" / "dev-entrypoint.sh",
|
||||
"backend/Makefile": REPO_ROOT / "backend" / "Makefile",
|
||||
}
|
||||
|
||||
# Shell terminators / redirects that end a simple command's argument list.
|
||||
@ -161,7 +162,7 @@ def test_sandbox_mkdir_precedes_uvicorn_launch(name):
|
||||
"""
|
||||
lines = LAUNCHERS[name].read_text(encoding="utf-8").splitlines()
|
||||
launch_idx = next((i for i, ln in enumerate(lines) if "uv run uvicorn" in ln), None)
|
||||
mkdir_idx = next((i for i, ln in enumerate(lines) if re.search(r"\bmkdir\b", ln) and "sandbox" in ln), None)
|
||||
mkdir_idx = next((i for i, ln in enumerate(lines) if re.search(r"\bmkdir\b", ln) and "sandbox" in ln.lower()), None)
|
||||
|
||||
assert launch_idx is not None, f"{name}: could not locate the 'uv run uvicorn' launch line"
|
||||
assert mkdir_idx is not None, f"{name}: could not locate the sandbox mkdir line"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user