Логотип Fusion Framework от Cipher UnitFusion

Async

Async-хендлеры и async middleware в Fusion Python

Обзор

Fusion поддерживает async HTTP-хендлеры и async middleware. Sync и async могут сосуществовать в одном приложении. Если любой middleware или сам хендлер async, этот запрос выполняется на общем asyncio runtime, связанном из Rust.

Async-хендлеры

Определите метод через async def:

from fusion_framework.api import FusionBaseApi
from fusion_framework.route import route
from fusion_framework import status


@route("api/[module]/")
class JobModule(FusionBaseApi):
    def get(self):
        return self.response({"mode": "sync"}, status=status.HTTP_SUCCESS)

    async def post(self):
        # await DB / HTTP / asyncio APIs here
        result = await do_work()
        return self.response(result, status=status.HTTP_201_CREATED)

Правила:

  • Та же привязка параметров, что у sync (path / body / query)
  • Те же self.response(...) / HTTPException
  • Не блокируйте event loop тяжёлым sync I/O внутри async def — используйте async-библиотеки или asyncio.to_thread

Async middleware

async def auth_middleware(request, call_next):
    token = (request.get("headers") or {}).get("authorization")
    if not token:
        return {"status": 401, "body": {"detail": "missing token"}}

    user = await load_user(token)  # your async call
    if not user:
        return {"status": 401, "body": {"detail": "invalid"}}

    request.setdefault("state", {})
    request["state"]["user"] = user
    return await call_next(request)

Регистрируйте как любой другой middleware:

MIDDLEWARE = [auth_middleware]

Важно: в async middleware всегда:

return await call_next(request)

Когда цепочка async, call_next возвращает awaitable.

Смешивание sync и async

def logging_mw(request, call_next):
    print(request["path"])
    return call_next(request)

async def timing_mw(request, call_next):
    import time
    t0 = time.perf_counter()
    response = await call_next(request)
    ms = (time.perf_counter() - t0) * 1000
    print(f"{request['path']} {ms:.1f}ms")
    return response

MIDDLEWARE = [logging_mw, timing_mw]

Если любой middleware в цепочке (или хендлер) — coroutine function, Fusion выполняет всю цепочку через await.

Полный пример

# main.py
import src.modules.jobs.jobs

from fusion_framework.app import FusionApp
from fusion_framework.config import get_settings, load_settings_module


async def attach_request_id(request, call_next):
    import uuid
    request.setdefault("state", {})
    request["state"]["request_id"] = str(uuid.uuid4())
    return await call_next(request)


MIDDLEWARE = [attach_request_id]


def main() -> None:
    load_settings_module("settings")
    app = FusionApp(get_settings())
    for mw in MIDDLEWARE:
        app.use(mw)
    app.listen()


if __name__ == "__main__":
    main()
# src/modules/jobs/jobs.py
from fusion_framework.api import FusionBaseApi
from fusion_framework.route import route
from fusion_framework import status


@route("api/[module]/")
class JobModule(FusionBaseApi):
    async def get(self):
        rid = self.state.get("request_id")
        data = await fetch_jobs()
        return self.response(
            {"request_id": rid, "jobs": data},
            status=status.HTTP_SUCCESS,
        )

Под капотом

  1. Rust принимает HTTP-запрос и диспатчит в Python bridge хендлера
  2. Выполняется цепочка middleware (sync- или async-путь)
  3. Async-работа отправляется в общий asyncio loop Fusion, чтобы параллельные запросы не блокировали друг друга

Event loop в main.py сами не запускаете — жизненным циклом сервера владеет app.listen().

Чеклист

ЦельПаттерн
Async API-методasync def get/post/...
Async middlewareasync def mw(request, call_next): return await call_next(request)
Регистрация глобального MWMIDDLEWARE + app.use в main.py
Чтение данных MW в хендлереself.state["…"]
Ошибкиraise HTTPException(...) (работает и в async-хендлерах)

См. также Middleware и Router.

На этой странице