Skip to main content

lru-cached-settings-pin-env-across-test-modules

An `@lru_cache` settings factory is a process-wide singleton, so the FIRST test module to touch it pins its monkeypatched env for the whole run. A second module setting a different secret/URL gets the first module's value — symptom is "passes alone, fails when run together" with a signature/connection error that points at the wrong thing.

설치로 이동

소스 정보

저장소
blas1n/claude-skills
최근 소스 활동
2026년 8월 8일 16:53
감지된 SKILL.md 언어
영어
스타
2
포크
0

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
lru-cached-settings-pin-env-across-test-modules
description
An `@lru_cache` settings factory is a process-wide singleton, so the FIRST test module to touch it pins its monkeypatched env for the whole run. A second module setting a different secret/URL gets the first module's value — symptom is "passes alone, fails when run together" with a signature/connection error that points at the wrong thing.
category
trap
# `@lru_cache`d settings pin env across test modules ## Problem Config factories are cached so construction cost is paid once: ```python @lru_cache(maxsize=1) def get_settings() -> Settings: """Return the process-wide Settings singleton (cached).""" return Settings() # reads os.environ via pydantic-settings ``` Two test modules each set their own secret and mint tokens with it: ```python # tests/api/test_a.py monkeypatch.setenv("USER_JWT_SECRET", "test-session-secret") # tests/mcp/test_b.py monkeypatch.setenv("USER_JWT_SECRET", "e2e-session-secret") ``` Whichever module runs first populates the cache. The second signs with its own secret while the server still verifies with the first one: ``` {"detail":"user JWT verification failed: Signature verification failed"} ``` The tells: - **Passes alone, fails together.** `pytest tests/api/test_a.py` is green; `pytest tests/mcp/test_b.py tests/api/test_a.py` is red. Run order decides which module wins, so it can also flip when you add an unrelated test file. - **The error blames the wrong layer.** "Signature verification failed" reads as a bug in token minting or key handling, not as config caching. - `monkeypatch` is doing its job perfectly — `os.environ` *is* correct. Nothing re-reads it. Same shape for any cached factory: a DB URL, an issuer, a feature flag, an API base. Anything behind `@lru_cache` / a module-level singleton. ## Solution ### Clear every cached factory the module influences, on both edges Not just the obvious one. A request often touches several settings objects (app config, authz config, worker config), each independently cached: ```python @pytest_asyncio.fixture async def db(monkeypatch): monkeypatch.setenv("USER_JWT_SECRET", SESSION_SECRET) monkeypatch.setenv("BSVIBE_OAUTH_ISSUER", ISSUER) get_settings.cache_clear() # authz Settings is @lru_cache(maxsize=1): whichever module touches it first # would otherwise pin its USER_JWT_SECRET for the whole process. get_authz_settings.cache_clear() yield ... get_settings.cache_clear() # clear on teardown too — the NEXT get_authz_settings.cache_clear() # module inherits whatever you left ``` Clearing only on setup leaves your value pinned for everyone after you. ### Find the cached factories ```bash grep -rn "lru_cache\|@cache" backend/ --include="*.py" | grep -B2 -i "settings\|config" ``` Then confirm which ones the code path under test actually reads — the import site tells you: `from x.settings import get_settings as get_authz_settings`. ### Diagnose an existing flake If a test passes alone and fails in a suite, bisect by pairing rather than reading the failing test: ```bash pytest tests/suspect_module.py tests/failing_module.py::test_x -q ``` A pass alone plus a fail when paired is near-conclusive for shared process state; cached settings are the first place to look. ## Related - `env-gated-test-backend-local-red-not-ci-red` - `pytest-singleton-async-resource-cross-loop-leak` - `feedback_drift_guard_cache_stale`
GitHub에서 보기