Запуск нескольких приложений asgi в одном потоке с помощью uvicorn

Я хочу запустить приложение 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.
  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

Как лучше это сделать?


person Dev Aggarwal    schedule 12.02.2020    source источник
comment
мне это кажется нормальным, что вам в этом не нравится, лучше каким образом? пришел сюда из github.com/encode/uvicorn/pull/510, который будет обрабатывать запуск нескольких uvicorns в нескольких потоках, поэтому это отличается от того, что вы спрашиваете, правильно ли я понял @ dev-aggarwal   -  person euri10    schedule 12.02.2020
comment
Да, я думаю, что искал то, чего не должен был: D. Извините за то, что отвлек вас!   -  person Dev Aggarwal    schedule 12.02.2020


Ответы (1)


Обновление - если у вас есть разделение путей между двумя приложениями, вы можете использовать это, чтобы пропустить промежуточное ПО 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)
person Dev Aggarwal    schedule 12.02.2020