Натрапив на просторах реддіта на репозиторій із переліком штук про котрі треба пам'ятати коли пишеш веб-сервіс на FastAPI.
Їх там зараз небагато, але всі дуже важливі. Мене найбільше зацікавив 9 пункт "Your dependencies may be running on threads" -
це може бути неочевидним, але якщо ваша async def view використовує синхронну залежність (навіть якщо вона нічого не робить а просто повертає примітивне значення)
то резолвінг цієї залежності буде відбуватись у тредпулі.
Тобто ось у цьому прикладі буде використовуватись тредпул незважаючи на те що root view використовує async def:
from fastapi import FastAPI, Depends
app = FastAPI()
def get_42():
return 42
@app.get("/")
async def root(value: int = Depends(get_42)):
return {"value": value}
Чим це погано? Тим що треди не резинові і за замовченням одночасно може жити лише 40 тредів, і якшо на ваш ендпоінт буде наплив трафіку, то перші 40 реквестів забʼють
тредпул, а решта буде чекати поки звільниться місце. Звісно що значення по-дефолту можна підняти, але воно всеодно не буде нескінченним.
Виправити у прикладі вище цю проблему просто - замінити def get_42(): на async def get_42(): і тоді всі реквести
будуть запускатись без тредпула, просто у поточному event loop.
Підсумовуючи:
- Завжди у першу чергу використовуйте async def для вьюх (це вже й так всі запамʼятали) і залежностей що інжектяться через Depends.
- Синхронні вьюхи використовуйте лише якщо вони роблять блокуючі операції, наприклад використовують бібліотеку requests для http запитів.
- Перевірте свої додатки - у тому ж пункті є код за допомогою якого можна це зробити
Лінки:
- https://github.com/Kludex/fastapi-tips
Їх там зараз небагато, але всі дуже важливі. Мене найбільше зацікавив 9 пункт "Your dependencies may be running on threads" -
це може бути неочевидним, але якщо ваша async def view використовує синхронну залежність (навіть якщо вона нічого не робить а просто повертає примітивне значення)
то резолвінг цієї залежності буде відбуватись у тредпулі.
Тобто ось у цьому прикладі буде використовуватись тредпул незважаючи на те що root view використовує async def:
from fastapi import FastAPI, Depends
app = FastAPI()
def get_42():
return 42
@app.get("/")
async def root(value: int = Depends(get_42)):
return {"value": value}
Чим це погано? Тим що треди не резинові і за замовченням одночасно може жити лише 40 тредів, і якшо на ваш ендпоінт буде наплив трафіку, то перші 40 реквестів забʼють
тредпул, а решта буде чекати поки звільниться місце. Звісно що значення по-дефолту можна підняти, але воно всеодно не буде нескінченним.
Виправити у прикладі вище цю проблему просто - замінити def get_42(): на async def get_42(): і тоді всі реквести
будуть запускатись без тредпула, просто у поточному event loop.
Підсумовуючи:
- Завжди у першу чергу використовуйте async def для вьюх (це вже й так всі запамʼятали) і залежностей що інжектяться через Depends.
- Синхронні вьюхи використовуйте лише якщо вони роблять блокуючі операції, наприклад використовують бібліотеку requests для http запитів.
- Перевірте свої додатки - у тому ж пункті є код за допомогою якого можна це зробити
Лінки:
- https://github.com/Kludex/fastapi-tips