Запустите несколько приложений ASGI в одной теме с Uvicorn - PullRequest
0 голосов
/ 12 февраля 2020

Я хочу запустить приложение Starlette и django в одном потоке.

(Наличие их в одном потоке обеспечивает быструю локальную связь между ними). ​​

Учитывая, что приложения asgi - это просто сопрограммы, я подумал, что это теоретически возможно с asyncio.gather().


Я придумал небольшой хак для этой работы, но у него есть некоторые ограничения.

from uvicorn import Server, Config

configs = [Config(app1, uds='app1.sock'), Config(app2, uds='app2.sock')]
coros = [Server(c).serve() for c in configs]

await asyncio.gather(*coros)

  1. Не поддерживает reload и workers options.
  2. Ctrl + C работает только для одного приложения.
INFO:     Started server process [86066]
INFO:     Waiting for application startup.
INFO:     Started server process [86066]
INFO:     Waiting for application startup.
INFO:     ASGI 'lifespan' protocol appears unsupported.
INFO:     Application startup complete.
INFO:     Uvicorn running on unix socket app1.sock (Press CTRL+C to quit)
INFO:     Application startup complete.
INFO:     Uvicorn running on unix socket app2.sock (Press CTRL+C to quit)
^CINFO:     Shutting down
INFO:     Finished server process [86066]
^C^C^C^C^C

Какой лучший способ сделать это?

1 Ответ

0 голосов
/ 12 февраля 2020

Обновление - Если у вас есть разделение путей между двумя приложениями, вы можете использовать это для пропуска промежуточного программного обеспечения Starlette:

from mydjangoapp.asgi import application as django_app

ws_app = Starlette(...)

async def app(scope, receive, send):
    path = scope.get("path")
    chosen = ws_app
    if not (path is None or path.startswith("/ws")):
        chosen = django_app
    return await chosen(scope, receive, send)

Глупый я! Starlette поддерживает монтирование произвольных приложений ASGI, что означает, что вы можете просто сделать следующее и использовать любой старый сервер ASGI из командной строки.

from mydjangoapp.asgi import application as django_app

app = Starlette(...)

app.mount('/', django_app)
...