#How to mount a WSGI sub-application

1 messages · Page 1 of 1 (latest)

low steeple
#

I've been struggling with a memory leak for a while. I'd like to try using PyLoot to analyze what's going on.

https://pypi.org/project/pyloot/

PyLoot gives the following example for Starlette and FastAPI, but I don't see a way to mount WSGI applications in Starlite. Any suggestions on how to tackle this?

from pyloot import PyLoot
from fastapi import FastAPI
from starlette.applications import Starlette
from starlette.middleware.wsgi import WSGIMiddleware

app = FastAPI()  # or Starlette()

pyloot = PyLoot()
app.on_event("startup")(pyloot.start)
app.mount("/_pyloot", WSGIMiddleware(pyloot.get_wsgi()))
tawdry frost
visual wrenBOT
tawdry frost
#

which has had some recent activity but not anything of substance yet

#

perahps a2wsgi will work for you?

quick kite
#

@brave vigil wanna add a draft PR?

#

Someone can take it over, maybe @tawdry frost

brave vigil
#

I can open a draft PR with the progress I made

#

It should be fully functional and is mainly missing tests and documentation

brave vigil
#

The starlette middleware is actually deprecated and they also recommend using this library as a replacement

low steeple
#

Thanks everyone!

@brave vigil I tried using a2wsgi... I'm probably not doing this correctly, but I'm getting errors in VSCode that state Argument of type "PyLootServer" cannot be assigned to parameter "app" of type "WSGIApp" in function "__init__" Type "PyLootServer" cannot be assigned to type "WSGIApp",

And when I try to start Starlite, I get an ImproperlyConfiguredException :

raise ImproperlyConfiguredException(  # pragma: no cover starlite.exceptions.http_exceptions.ImproperlyConfiguredException: 500: Parameter '' with type 'typing.Callable[[typing.Union[starlite.types.asgi_types.HTTPScope, starlite.types.asgi_types.WebSocketScope], typing.Callable[..., typing.Awaitable[typing.Union[starlite.types.asgi_types.HTTPRequestEvent, starlite.types.asgi_types.HTTPDisconnectEvent, starlite.types.asgi_types.WebSocketConnectEvent, starlite.types.asgi_types.WebSocketReceiveEvent, starlite.types.asgi_types.WebSocketDisconnectEvent]]], typing.Callable[[typing.Union[starlite.types.asgi_types.HTTPResponseStartEvent, starlite.types.asgi_types.HTTPResponseBodyEvent, starlite.types.asgi_types.HTTPServerPushEvent, starlite.types.asgi_types.HTTPDisconnectEvent, starlite.types.asgi_types.WebSocketAcceptEvent, starlite.types.asgi_types.WebSocketSendEvent, starlite.types.asgi_types.WebSocketResponseStartEvent, starlite.types.asgi_types.WebSocketResponseBodyEvent, starlite.types.asgi_types.WebSocketCloseEvent]], typing.Awaitable[NoneType]]], typing.Awaitable[NoneType]]' could not be mapped to an Open API type. This can occur if a user-defined generic type is resolved as a parameter. If '' should not be documented as a parameter, annotate it using the Dependency function, e.g.,  : ... = Dependency(...).
#

Here's an mcve:

import uvicorn
from a2wsgi import WSGIMiddleware
from pyloot import PyLoot
from starlite import Starlite, get
from starlite.types import ASGIApp, Receive, Scope, Send

loot = PyLoot()
loot.start()


@get("/pyloot")
def pyloot_router() -> ASGIApp:
    async def my_asgi_app(scope: Scope, receive: Receive, send: Send) -> None:
        WSGIMiddleware(loot.get_wsgi())

    return my_asgi_app


@get("/")
def home() -> dict[str, str]:
    return {"hello": "world"}


app = Starlite(
    route_handlers=[home, pyloot_router],
    debug=True,
)

if __name__ == "__main__":
    uvicorn.run(app, host="127.0.0.1", port=8000)

#

Running on starlite == 1.51.10 and Python 3.11

brave vigil
#

You wrap the application in it, but then you're not doing anything with that

#

Try replacing return my_asgi_app with return WSGIMiddleware(loot.get_wsgi())

#

Also, the proper way to mount an asgi application is to use the asgi route handler decorator

#
from starlite import Starlite, asgi
from a2wsgi import WSGIMiddleware
from pyloot import PyLoot

loot = PyLoot()
loot.start()

pyloot_handler = asgi("/pyloot")(WSGIMiddleware(loot.get_wsgi()))

app = Starlite([pyloot_handler])
#

This should work

low steeple
#

@brave vigil thanks so much for the help here. I tried running the code you have, but it gave errors about Pyloot not supporting multi-processing environments. So I used the wrapper function shown in Pyloot's docs to solve this. It looks like Pyloot is mounted now, but I'm getting an 404 response from Pyloot server:

"GET /pyloot HTTP/1.1" 404 Not Found
pyloot.server - server - [_dispatch] path_info=/pyloot path=/pyloot

It's probably a question for the pyloot maintainer, but here's the latest version of the MCVE for visibility:

from a2wsgi import WSGIMiddleware
from pyloot import PyLoot
from starlite import Starlite, asgi

loot = PyLoot()
loot.start()


def pyloot_wrapper(wsgi_environ, start_response):
    pyloot_environ = wsgi_environ.copy()
    pyloot_environ["wsgi.multiprocess"] = False
    wsgi = loot.get_wsgi()
    return wsgi(pyloot_environ, start_response)


pyloot_handler = asgi("/pyloot")(WSGIMiddleware(pyloot_wrapper))

app = Starlite(
    [pyloot_handler],
    debug=True,
)
brave vigil
#

Hm

#

I'm not so sure about that. How are you running the app?

low steeple
#

uvicorn main-pyloot:app --reload

brave vigil
#

Not sure why pyloot thinks it's a multi-process environment then?

#

Uvicorn is single-process by default

low steeple
#

Could it be the WSGIMiddleware? I noticed it sets default workers to 10. I tried setting workers to 1, but I still got the multiprocessing error, so I used the wrapper that their docs suggested and that seemed to fix it

brave vigil
#

The middleware uses a threads, not processes tho

#

I guess it sets environ["wsgi.multiprocess"] = True because it could be a multi-process environment

#

Do you mind opening a discussion on GitHub to track this?

low steeple
#

Happy to. In Pyloot's github though, right?

brave vigil
#

I meant our repo 😄

#

Just so we can track this more easily

low steeple
#

Haha, sure thing!

#

I was thinking that since Pyloot server seems to be mounted to Litestar, but pyloot server can't find the endpoint, that the issue is maybe on the Pyloot side of things

#

But I'll open a ticket in Litestar now 🙂

brave vigil
#

Uhm

#

I just checked the pyloot docs

#

It suggests that path should be _pyloot, not pyloot

#

Maybe that makes a difference somehow?

low steeple
#

I did try that earlier, but no difference, I get the same error (logs below).

Good catch though, I should have left the underscore in the pathing since that's what the Pyloot docs recommended.

INFO:     127.0.0.1:65528 - "GET /_pyloot HTTP/1.1" 404 Not Found
INFO - 2023-04-14 12:37:29,653 - pyloot.server - server - [_dispatch] path_info=/_pyloot path=/_pyloot