11

When I use aiohttp.web.run_app(. . ., port=0), I assume that it selects an arbitrary available port on which to serve. Is this correct? And if so, is there some way to figure out what port it's selected?

abingham
  • 1,294
  • 1
  • 10
  • 17
  • yes that assumption is correct – Corey Goldberg Jun 18 '17 at 00:38
  • If it works something like `flask`, It will chose a random port.... Starting flask with port 0 will choose random high port number. – Yuval Pruss Jun 18 '17 at 07:42
  • Right, but how do I know which? Is there an attribute on the app or loop? – abingham Jun 18 '17 at 07:49
  • 1
    No way. But why do you need it? Starting server on random port isn't look very useful – Andrew Svetlov Jun 18 '17 at 09:42
  • 1
    It's a refactoring server used by e.g. emacs. Users don't (and shouldn't normally) care which port it uses, but emacs needs to know how to talk to it after it starts. The current bottle-based version is able to print the port it chooses to stdout, and emacs parses that. I need something similar for aiohttp. – abingham Jun 18 '17 at 10:30

2 Answers2

6

You use server.sockets as in the following code:

@asyncio.coroutine
def status(request):
    """Check that the app is properly working"""
    return web.json_response('OK')


app = web.Application()  # pylint: disable=invalid-name
app.router.add_get('/api/status', status)


def main():
    """Starts the aiohttp process to serve the REST API"""
    loop = asyncio.get_event_loop()
     # continue server bootstraping
    handler = app.make_handler()
    coroutine = loop.create_server(handler, '0.0.0.0', 0)
    server = loop.run_until_complete(coroutine)
    print('Serving on http://%s:%s' % server.sockets[0].getsockname()) # HERE!
    try:
        loop.run_forever()
    except KeyboardInterrupt:
        pass
    finally:
        server.close()
        loop.run_until_complete(server.wait_closed())
        loop.run_until_complete(handler.finish_connections(1.0))
        loop.close()
amirouche
  • 7,682
  • 6
  • 40
  • 94
  • 2
    make_handler() is now deprecated. Can someone suggest an alternative recipe? https://docs.aiohttp.org/en/stable/web_reference.html#aiohttp.web.Application.make_handler – Jason Jul 05 '21 at 13:58
  • You can use `site._server.sockets[0].getsockname()` – Albert Peschar Nov 09 '22 at 12:39
1

When using application runners, you can pass in port 0 and access the selected port via the site object:

runner = web.AppRunner(app)
await runner.setup()

site = web.TCPSite(runner, 'localhost', 0)
await site.start()

print('Serving on http://%s:%s' % site._server.sockets[0].getsockname())
Albert Peschar
  • 521
  • 3
  • 4