mirror of https://github.com/tiangolo/fastapi.git
Merge 6b465e7ed0 into 0127069d47
This commit is contained in:
commit
7afd888ac2
|
|
@ -28,6 +28,7 @@ from typing import (
|
||||||
TypeVar,
|
TypeVar,
|
||||||
cast,
|
cast,
|
||||||
)
|
)
|
||||||
|
from weakref import WeakKeyDictionary
|
||||||
|
|
||||||
import anyio
|
import anyio
|
||||||
from annotated_doc import Doc
|
from annotated_doc import Doc
|
||||||
|
|
@ -248,15 +249,17 @@ class _DefaultLifespan:
|
||||||
|
|
||||||
|
|
||||||
# Cache for endpoint context to avoid re-extracting on every request
|
# Cache for endpoint context to avoid re-extracting on every request
|
||||||
_endpoint_context_cache: dict[int, EndpointContext] = {}
|
_endpoint_context_cache: WeakKeyDictionary[Any, EndpointContext] = WeakKeyDictionary()
|
||||||
|
|
||||||
|
|
||||||
def _extract_endpoint_context(func: Any) -> EndpointContext:
|
def _extract_endpoint_context(func: Any) -> EndpointContext:
|
||||||
"""Extract endpoint context with caching to avoid repeated file I/O."""
|
"""Extract endpoint context with caching to avoid repeated file I/O."""
|
||||||
func_id = id(func)
|
try:
|
||||||
|
cached = _endpoint_context_cache.get(func)
|
||||||
if func_id in _endpoint_context_cache:
|
except TypeError:
|
||||||
return _endpoint_context_cache[func_id]
|
cached = None
|
||||||
|
if cached is not None:
|
||||||
|
return cached
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ctx: EndpointContext = {}
|
ctx: EndpointContext = {}
|
||||||
|
|
@ -270,7 +273,10 @@ def _extract_endpoint_context(func: Any) -> EndpointContext:
|
||||||
except Exception:
|
except Exception:
|
||||||
ctx = EndpointContext()
|
ctx = EndpointContext()
|
||||||
|
|
||||||
_endpoint_context_cache[func_id] = ctx
|
try:
|
||||||
|
_endpoint_context_cache[func] = ctx
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import gc
|
||||||
|
import weakref
|
||||||
|
|
||||||
|
from fastapi.routing import _endpoint_context_cache, _extract_endpoint_context
|
||||||
|
|
||||||
|
|
||||||
|
def _make_endpoint():
|
||||||
|
def endpoint():
|
||||||
|
return None
|
||||||
|
|
||||||
|
return endpoint
|
||||||
|
|
||||||
|
|
||||||
|
def test_endpoint_context_cache_releases_endpoints():
|
||||||
|
endpoint = _make_endpoint()
|
||||||
|
_extract_endpoint_context(endpoint)
|
||||||
|
assert endpoint in _endpoint_context_cache
|
||||||
|
|
||||||
|
ref = weakref.ref(endpoint)
|
||||||
|
size_with_endpoint = len(_endpoint_context_cache)
|
||||||
|
del endpoint
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
assert ref() is None
|
||||||
|
assert len(_endpoint_context_cache) <= size_with_endpoint - 1
|
||||||
Loading…
Reference in New Issue