Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple serverless platforms #86

Closed
lsorber opened this issue Feb 9, 2020 · 9 comments
Closed

Support multiple serverless platforms #86

lsorber opened this issue Feb 9, 2020 · 9 comments
Labels
feature New feature or request

Comments

@lsorber
Copy link
Contributor

lsorber commented Feb 9, 2020

This comment [1] explains how to use Mangum with the serverless framework. Since serverless supports multiple providers (e.g., Azure), would it be possible that Mangum enables ASGI support for other providers too?

[1] https://dev.to/anilgrexit/comment/gkfo

@jordaneremieff
Copy link
Owner

jordaneremieff commented Feb 9, 2020

So initially this is something I was considering here and Mangum used to support Azure specifically, but I ended up splitting that support out into a separate package https://github.com/erm/bonnette and have done something similar with Google Cloud Functions in https://github.com/erm/grevillea.

The adapter logic is essentially the same in these projects, but I don't really maintain them. It has crossed my mind to re-add support for multiple providers (or find some way of sharing the adapter logic across the separate projects), but I'm not really sure. I'll leave this issue open, if there is enough interest I'll take a serious look into doing so.

@jordaneremieff jordaneremieff added the maybe Just an idea label Feb 9, 2020
@lsorber
Copy link
Contributor Author

lsorber commented Feb 9, 2020

That's nice to hear, and thanks for the pointers.

The reason I posted this issue is because I think it would be great to be able to use the awesome FastAPI package across AWS Lambda, Azure Functions, and Google Cloud Functions.

If it helps, here's one other example of people with the same interest: tiangolo/fastapi#812

@jordaneremieff jordaneremieff added the feedback needed Additional opinions and perspectives are needed label Aug 1, 2020
@Nagalenoj
Copy link

I was looking to use FastAPI with Google Cloud Funtions and landed over here. Agree with @lsorber .

@jordaneremieff
Copy link
Owner

jordaneremieff commented Sep 23, 2020

@Nagalenoj Okay, I'll think about how to approach this, but I probably won't be able to start on it for awhile, not sure when. Most likely I will support multiple providers in this project.

@jordaneremieff jordaneremieff added feature New feature or request and removed feedback needed Additional opinions and perspectives are needed maybe Just an idea labels Sep 24, 2020
@jordaneremieff
Copy link
Owner

So I started doing some investigation into how I might accomplish this. I'm thinking adapter classes will look like this:

@dataclass
class Adapter:

    options: dict

    def __call__(self, *args) -> Any:
        raise NotImplementedError

    def on_request(self) -> None:
        raise NotImplementedError

    def on_response(self) -> None:
        raise NotImplementedError

    def on_response_error(self) -> None:
        raise NotImplementedError

The options dict would replace all the platform-specific configuration (e.g. api_gateway_base_path) and the main Mangum class would still be the common interface for creating the adapter instances and running the ASGI cycles:

@dataclass
class Mangum:
    """
    Creates an adapter instance.

    * **app** - An asynchronous callable that conforms to version 3.0 of the ASGI
    specification. This will usually be an ASGI framework application instance.
    * **lifespan** - A string to configure lifespan support. Choices are `auto`, `on`,
    and `off`. Default is `auto`.
    * **provider** - A string value identifier for the platform. Choices are `aws`,
    `azure`, and `google`. Default is `aws`.
    * **options** - A dictionary mapping of provider-specific configuration.
    """

    app: ASGIApp
    lifespan: str = "auto"
    provider: str = "aws"
    options: dict = field(default_factory=dict)

    def __post_init__(self) -> None:
        if self.lifespan not in ("auto", "on", "off"):  # pragma: no cover
            raise ConfigurationError(
                "Invalid argument supplied for `lifespan`. Choices are: auto|on|off"
            )
        if self.provider == "aws":
            from mangum.adapters.aws import AWSAdapter

            self.adapter = AWSAdapter(self.options)

        elif self.provider == "azure":
            from mangum.adapters.azure import AzureAdapter

            self.adapter = AzureAdapter(self.options)

        elif self.provider == "google":
            from mangum.adapters.google import GoogleAdapter

            self.adapter = GoogleAdapter(self.options)

    def __call__(self, *args) -> dict:
        with ExitStack() as stack:
            if self.lifespan != "off":
                lifespan_cycle: typing.ContextManager = LifespanCycle(
                    self.app, self.lifespan
                )
                stack.enter_context(lifespan_cycle)

            http_cycle = self.adapter(*args)
            response = http_cycle(self.app)

            return response

My intention is to implement this with support for Azure and GCF to start since I already have some work to base them on, but it should be able to support any similar platforms. Ideally I can find a way to determine the platform at runtime without specifying the providers parameter, otherwise the default configuration will be set to aws to avoid breaking existing usage. I'm not sure when I'll have this ready for a PR/release because there is a lot involved to get it properly ready, but I'm slowly working/thinking on it.

@jordaneremieff jordaneremieff changed the title Support for other Serverless providers (e.g., Azure) Support multiple Serverless platforms Sep 27, 2020
@jordaneremieff jordaneremieff changed the title Support multiple Serverless platforms Support multiple serverless platforms Sep 27, 2020
@jordaneremieff
Copy link
Owner

jordaneremieff commented Oct 17, 2020

After doing some further investigation I ran across Azure/azure-functions-python-worker#165. The azure-functions-python-worker introduced a WSGI middleware, so it probably makes more sense to PR ASGI support into that package rather than trying to shoe-horn support into this package directly. Also it appears that async function definitions are supported , so it could be implemented differently than here. In the case of Google Cloud Functions, perhaps that will offer greater ASGI support in future as well - it already uses Flask requests, so it doesn't seem outside of the realm of possibility as ASGI grows in popularity.

The maintenance burden of keeping up with these external developments seems quite high, especially since I only really use AWS Lambda myself, so it seems to make more sense to not include this here.

There are still potentially ways to share the generic behaviour for other use-cases/packages - I'll have to think about what this means exactly, will keep this issue open and update it with my thoughts later.

@jordaneremieff
Copy link
Owner

I created an issue here to explore the Azure use-case.

@lsorber
Copy link
Contributor Author

lsorber commented Oct 18, 2020

Makes sense @jordaneremieff. Thank you for taking the time to explore what a solution could look like, and for helping to kick-start a proper integration.

Unrelated: you've got some creative project names, how do you come up with those if I may ask?

@jordaneremieff
Copy link
Owner

@lsorber No worries. I think most of what is in here can be re-purposed without too much effort. I'll base anything further about this on how the Azure functions library might approach ASGI, will just let this ticket hang around in the meantime. I might just end up copying over anything relevant from Mangum to Grevillea specifically when I next look into GCF.

Also, Mangum & Bonnette are named after my two favourite musicians, Jeff Mangum of Neutral Milk Hotel and Sean Bonnette of AJJ. Grevillea (spider flower) is the genus of my favourite plant, Grevillea Buxifolia. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants