Browse Source

Add docs for dependency parallelization. (#639)

pull/13756/head
Fodor Zoltan 10 months ago
parent
commit
0737bc21b5
  1. 52
      docs/en/docs/advanced/advanced-dependencies.md
  2. 1
      docs/en/docs/reference/dependencies.md
  3. 3
      docs_src/dependencies/parallel_global_opt_in.py
  4. 13
      docs_src/dependencies/parallel_per_dep_disable.py
  5. 17
      docs_src/dependencies/parallel_per_dep_enable.py
  6. 14
      docs_src/dependencies/parallel_security.py

52
docs/en/docs/advanced/advanced-dependencies.md

@ -1,5 +1,57 @@
# Advanced Dependencies { #advanced-dependencies }
## Parallel dependency resolution (opt-in) { #parallel-dependency-resolution-opt-in }
FastAPI can resolve independent dependencies in parallel to reduce overall latency.
This is disabled by default. You can opt in per-application, and you can also control
it per dependency.
- Application-wide default (disabled by default):
- Set `depends_default_parallelizable=True` in `FastAPI(...)` to allow parallel
resolution by default.
- Per-dependency override:
- Use `Depends(..., parallelizable=True | False)` (and the same for `Security(...)`).
- If not provided, the application default is used.
When parallelization is enabled, dependencies at the same level of the dependency graph
that are not "context sensitive" will be resolved concurrently.
Context sensitive dependencies are always resolved sequentially:
- Dependencies implemented with `yield` (generator or async generator dependencies).
- Dependencies explicitly marked with `parallelizable=False`.
Dependency errors are still raised in the order of declaration, even if resolved in
parallel. Caching (`use_cache=True`, the default) still works per request: concurrent
callers share a single in-flight execution and the same result.
### Enable globally
{* ../../docs_src/dependencies/parallel_global_opt_in.py *}
### Enable/disable per dependency
{* ../../docs_src/dependencies/parallel_per_dep_enable.py *}
You can also opt out for a specific dependency when the app default is parallel:
{* ../../docs_src/dependencies/parallel_per_dep_disable.py *}
### Security dependencies
`Security(...)` supports the same `parallelizable` flag. Caching for security dependencies
respects OAuth2 scopes: dependencies with the same scopes share a cached value within
one request, different scopes result in separate executions.
{* ../../docs_src/dependencies/parallel_security.py *}
### Notes
- Sync (regular `def`) dependencies participate via a threadpool.
- Generator (`yield`) dependencies are always sequential.
- Errors from dependencies are raised respecting the declaration order.
## Parameterized dependencies { #parameterized-dependencies }
All the dependencies we have seen are a fixed function or class.

1
docs/en/docs/reference/dependencies.md

@ -5,7 +5,6 @@
Dependencies are handled mainly with the special function `Depends()` that takes a callable.
Here is the reference for it and its parameters.
You can import it directly from `fastapi`:
```python

3
docs_src/dependencies/parallel_global_opt_in.py

@ -0,0 +1,3 @@
from fastapi import FastAPI
app = FastAPI(depends_default_parallelizable=True)

13
docs_src/dependencies/parallel_per_dep_disable.py

@ -0,0 +1,13 @@
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI(depends_default_parallelizable=True)
async def dep_seq() -> int:
return 1
@app.get("/users")
async def read_users(
x: Annotated[int, Depends(dep_seq, parallelizable=False)],
):
return {"x": x}

17
docs_src/dependencies/parallel_per_dep_enable.py

@ -0,0 +1,17 @@
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI(depends_default_parallelizable=False)
async def dep_a() -> int:
return 1
async def dep_b() -> int:
return 2
@app.get("/items")
async def read_items(
a: Annotated[int, Depends(dep_a, parallelizable=True)],
b: Annotated[int, Depends(dep_b, parallelizable=True)],
):
return {"a": a, "b": b}

14
docs_src/dependencies/parallel_security.py

@ -0,0 +1,14 @@
from typing import Annotated
from fastapi import FastAPI, Security
app = FastAPI(depends_default_parallelizable=True)
async def get_api_key() -> str:
return "secret"
@app.get("/secure")
async def secure(
k1: Annotated[str, Security(get_api_key, scopes=["a"], parallelizable=True)],
k2: Annotated[str, Security(get_api_key, scopes=["b"], parallelizable=True)],
):
return {"ok": True, "k1": k1, "k2": k2}
Loading…
Cancel
Save