Skip to content

fix(tracking): run the Burr UI lifespan when it is mounted with mount_burr_ui() - #1041

Open
YongGoose wants to merge 1 commit into
apache:mainfrom
YongGoose:fix/mount-burr-ui-lifespan
Open

YongGoose wants to merge 1 commit into
apache:mainfrom
YongGoose:fix/mount-burr-ui-lifespan

Conversation

@YongGoose

Copy link
Copy Markdown
Member

Fixes #1040.

Starlette does not run the lifespan of a mounted sub-app. Because of that, when the Burr UI is mounted with mount_burr_ui(), its lifespan never runs: /ready stays 503, and the backend's startup never happens (its lifespan hook, snapshot download, and the indexing/snapshot jobs).

Changes

  • mount_burr_ui() now wraps the parent app's router.lifespan_context. The UI's lifespan runs around the parent's, and the parent's own lifespan and any state it yields are kept.
  • The docstring notes that the UI's startup and shutdown run inside the parent's lifespan, so mount_burr_ui() has to be called before the parent app starts.
  • Added tests/tracking/test_server_mount.py. There were no tests for mount_burr_ui() before.

How I tested this

  • New tests: the mounted /burr/ready returns 200, and a parent lifespan still runs, with the state it yields reaching requests. Both tests fail on main and pass with this change.
  • examples/fastapi_mount_example.py under uvicorn examples.fastapi_mount_example:app with BURR_SERVE_STATIC=false: /burr/ready returned 503 before the change and 200 after.
  • Full tests/ suite in Linux containers, excluding the persister integration and Bedrock tests: Python 3.12 had 765 passed and 1 skipped; Python 3.10 had 763 passed and 3 skipped.
  • black, isort, flake8 (pre-commit versions) and scripts/check_asf_headers.py on the changed files.

Notes

  • I tested with the default local backend only. The S3 backend's startup goes through the same lifespan, but I have not run it.
  • The test sets BURR_SERVE_STATIC=false before importing burr.tracking.server.run, because importing that module builds an app that serves the UI build, which a source checkout does not have.
  • run.initialized is a module-level flag that is never reset, so the tests reset it with monkeypatch.

Checklist

  • PR has an informative and human-readable title (this will be pulled into the release notes)
  • Changes are limited to a single goal (no scope creep)
  • Code passed the pre-commit check & code is left cleaner/nicer than when first encountered.
  • Any change in functionality is tested
  • New functions are documented (with a description, list of inputs, and expected output)
  • Placeholder code is flagged / future TODOs are captured in comments
  • Project documentation has been updated if adding/changing functionality.

🤖 Generated with Claude Code

Starlette does not run the lifespan of a mounted sub-app, so with
mount_burr_ui() the Burr UI's lifespan never ran: /ready stayed 503 and the
backend's startup (its lifespan hook, indexing and snapshot jobs) never
started. mount_burr_ui() now runs the UI's lifespan around the parent app's,
keeping the parent's own lifespan and the state it yields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the area/tracking Telemetry, tracing, OpenTelemetry label Nov 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/tracking Telemetry, tracing, OpenTelemetry

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mount_burr_ui() never runs the Burr UI's lifespan, so /ready stays 503

1 participant