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

Update fake_server.py example/ provide full example how to create truly asynchronous server #3742

Closed
jsdevtom opened this issue May 9, 2019 · 4 comments
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers

Comments

@jsdevtom
Copy link

jsdevtom commented May 9, 2019

Long story short

https://github.com/aio-libs/aiohttp/blob/master/examples/fake_server.py#L37 is outdated.

https://docs.aiohttp.org/en/stable/web_advanced.html#application-runners states that:

run_app() provides a simple blocking API for running an Application.
For starting the application asynchronously or serving on multiple HOST/PORT AppRunner exists.

No up to date example exists however on how exactly to implement the truly async server

Expected behaviour

Replicating the example doesn't cause DeprecationWarning: loop argument is deprecated

Actual behaviour

Replicating the example causes DeprecationWarning: loop argument is deprecated

Steps to reproduce

Replicating the example found linked above. Or in my exact case:

server.py

import asyncio

from multidict import MultiDictProxy
from aiohttp import web

routes = web.RouteTableDef()
loop = asyncio.get_event_loop()


class Server:

    def __init__(self, *, inner_loop):
        self.loop = inner_loop
        self.app = web.Application(loop=loop)
        self.app.add_routes(routes)
        self.runner = None

    async def start(self):
        port = 40509
        self.runner = web.AppRunner(self.app)
        await self.runner.setup()
        site = web.TCPSite(self.runner, port=port)
        await site.start()

    @routes.get('/')
    async def on_query(self, request):
        query: MultiDictProxy = request.query.get('q')

        await asyncio.sleep(5)

        if query:
            return web.json_response({'query': query})

        return web.json_response({})


async def main(main_loop):
    server = Server(inner_loop=main_loop)
    await server.start()


try:
    loop.run_until_complete(main(loop))
except KeyboardInterrupt:
    loop.close()

requirements.py

pythonwhois==2.4.3
aiohttp==3.5.4
cchardet==2.1.4
aiodns==2.0.0

Dockerfile

FROM python:3.7.3
WORKDIR /app
COPY ./requirements.txt /app
COPY ./server.py /app
RUN pip install -r ./requirements.txt
CMD ["python", "/app/server.py"]

Then run docker build . -t py-whois && docker run py-whois

Your environment

Docker image python:3.7.3-alpine3.9 (see above)

@asvetlov
Copy link
Member

Keeping examples up to date is important, I agree.
Pull request to fix them are welcome!
I have questions for your snippet though:

  1. loop should be avoided. Early binding a loop on module level is a bad practice.
  2. Replace loop.run_until_complete() with asyncio.run() to follow best practices.
  3. IMHO Server.start() finishes just after the server creation. Need to add something to serve incoming requests for more long time
  4. RouteTableDef doesn't support methods in decorators.

@jsdevtom
Copy link
Author

Thank you for the prompt response. Points 3 and 4 I realized later but 1 and 2 I didn't realize thanks for the knowledge!

@mjpieters
Copy link
Contributor

The example has been updated to remove the loop argument in #3580. Are there other updates needed still?

@mjpieters mjpieters added documentation Improvements or additions to documentation good first issue Good for newcomers labels Sep 19, 2019
@mjpieters
Copy link
Contributor

We’ve confirmed this is covered now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants