Unify the teardown-on-shutdown attach behind one guarded seam#130
Merged
Conversation
One method owns teardown-attach detection (a uniform _lite_bootstrap_teardown_attached marker), the double-attach warning, and the skip. Framework bootstrappers will route their per-framework attach through it. Directly unit-tested against a dummy target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both bootstrappers now call BaseBootstrapper._attach_teardown_once with a framework-specific attach thunk. FastAPI's lifespan merge moves to _wrap_lifespan and its marker renames to the unified _lite_bootstrap_teardown_attached; FastMCP migrates from structural _TeardownProvider detection to the marker (the provider remains the attach mechanism). Behavior preserved; warning wording unified. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both now route their on_shutdown attach through _attach_teardown_once, gaining the double-attach warning they previously lacked. New tests assert a second bootstrapper on the same target warns (Litestar also: on_shutdown not stacked). attach thunk typed Callable[[], object] since FastStream's on_shutdown returns the callback. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Set the teardown marker only AFTER attach() succeeds, so a raising attach leaves the target untagged and a retry can re-attach (was: permanent skip). - Reword the warning to cover the config target (Litestar tags AppConfig, not an app), keeping the remediation accurate. - Move Litestar's application_config.debug mutation into the attach thunk so a skipped second bootstrapper mutates nothing. - Regression test: a failed attach does not mark the target. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Moves "register this bootstrapper's
teardownto run on the framework's shutdown" behind one seam:BaseBootstrapper._attach_teardown_once(target, attach). That method owns detection (a uniform_lite_bootstrap_teardown_attachedmarker), the double-attach warning, and the skip. Each app-bearing bootstrapper's__init__shrinks to "here is my target, here is how I attach."Why
The teardown-attach was wired five different ways. The double-attach guard + warning was copy-pasted between FastAPI and FastMCP (with two different detection mechanisms — a marker vs a structural provider check) and absent from Litestar and FastStream, so the same user error (two bootstrappers on one app) warned on two frameworks and silently double-registered
teardownon the other two. (Candidate 2 of the 2026-06-23 architecture review.)Changes
base.py— new_attach_teardown_once+_TEARDOWN_MARKER;attachtypedCallable[[], object](FastStream'son_shutdownreturns the callback)._wrap_lifespan, marker renamed to the unified name; FastMCP migrates structural detection → marker (the_TeardownProviderstays as the attach mechanism).architecture/bootstrappers.md(new "Teardown-on-shutdown attach" section + sentinel convention),CLAUDE.md; bundle underplanning/changes/2026-06-24.01-unify-teardown-attach/.Behavior change
Litestar and FastStream now emit a warning when a second bootstrapper is constructed against the same app/config. Intended consistency, non-fatal (warn + skip); the first bootstrapper's teardown still runs.
Verification
199 passed, 100% coverage;just lintclean (ruff+ty). FastAPI/FastMCP behavior preserved (lifespan not re-wrapped / single_TeardownProvider).🤖 Generated with Claude Code