2017-06-30 5 views
6

Können zwei aiohttp.web.Application() Objekte in demselben Prozess ausgeführt werden, z. an verschiedenen Ports?Mehrere aiohttp Application() läuft im selben Prozess?

Ich sehe eine Reihe von Beispielen für aiohttp Code wie:

from aiohttp import web 
app = web.Application() 
app.router.add_get('/foo', foo_view, name='foo') 
web.run_app(app, host='0.0.0.0', port=10000) 

Ich frage mich, ob es eine gleichwertige ist, wo mehrere web.Applications() können gleichzeitig ausgeführt konfiguriert werden. Etwas wie:

from aiohttp import web 
app1 = web.Application() 
app1.router.add_get('/foo', foo_view, name='foo') 
app2 = web.Application() 
app2.router.add_get('/bar', bar_view, name='bar') 
# This is the wishful thinking code: 
web.configure_app(app1, host='0.0.0.0', port=10000) 
web.configure_app(app2, host='0.0.0.0', port=10001) 
web.run_apps() 

Mein Anwendungsfall ist, dass ich einen vorhandenen Python-Web-Framework, die diese Art der Sache tut, und ich baue einen Prototyp, der in Python 3.6 mit aiohttp analog ist.

Ich verstehe, dass mehrere Python-Server hinter z. nginx (siehe auch http://aiohttp.readthedocs.io/en/stable/deployment.html); das ist nicht das was ich suche. Ich möchte die Möglichkeit von zwei aiohttp Webservern mit der gleichen asyncio Ereignisschleife erforschen, die in demselben Python-Prozess läuft und an zwei verschiedenen Häfen dient.

Antwort

5

Ja, Sie können - einfach einen Wrapper mit Re-Implementierung von run_app schreiben.

Hier ist ein einfaches Beispiel. Alle appspezifischen Teile von run_app werden in die dedizierte Klasse AppWrapper verschoben. Die MultiApp ist nur dafür zuständig, alle konfigurierten Apps zu initialisieren, die Schleife zu durchlaufen und aufzuräumen.

import asyncio 
from aiohttp import web 


class AppWrapper: 

    def __init__(self, aioapp, port, loop): 
     self.port = port 
     self.aioapp = aioapp 
     self.loop = loop 
     self.uris = [] 
     self.servers = [] 

    def initialize(self): 
     self.loop.run_until_complete(self.aioapp.startup()) 
     handler = self.aioapp.make_handler(loop=self.loop) 

     server_creations, self.uris = web._make_server_creators(
      handler, loop=self.loop, ssl_context=None, 
      host=None, port=self.port, path=None, sock=None, 
      backlog=128) 

     self.servers = self.loop.run_until_complete(
      asyncio.gather(*server_creations, loop=self.loop) 
     ) 

    def shutdown(self): 
     server_closures = [] 
     for srv in self.servers: 
      srv.close() 
      server_closures.append(srv.wait_closed()) 
     self.loop.run_until_complete(
      asyncio.gather(*server_closures, loop=self.loop)) 

     self.loop.run_until_complete(self.aioapp.shutdown()) 

    def cleanup(self): 
     self.loop.run_until_complete(self.aioapp.cleanup()) 

    def show_info(self): 
     print("======== Running on {} ========\n".format(', '.join(self.uris))) 


class MultiApp:  

    def __init__(self, loop=None): 
     self._apps = [] 
     self.user_supplied_loop = loop is not None 
     if loop is None: 
      self.loop = asyncio.get_event_loop() 
     else: 
      self.loop = loop 

    def configure_app(self, app, port): 
     app._set_loop(self.loop) 
     self._apps.append(
      AppWrapper(app, port, self.loop) 
     ) 

    def run_all(self): 
     try: 
      for app in self._apps: 
       app.initialize() 
      try: 
       for app in self._apps: 
        app.show_info() 
       print("(Press CTRL+C to quit)") 
       self.loop.run_forever() 
      except KeyboardInterrupt: # pragma: no cover 
       pass 
      finally: 
       for app in self._apps: 
        app.shutdown() 
     finally: 
      for app in self._apps: 
       app.cleanup() 

     if not self.user_supplied_loop: 
      self.loop.close() 

Hinweis: beachten Sie die Verwendung von internen aiohttp ‚s Methode, das Subjekt der Veränderung sein kann.

machen wir es nun mit:

from aiohttp import web 

async def handle1(request): 
    return web.Response(text='SERVER 1') 


async def handle2(request): 
    return web.Response(text='SERVER 2') 

app1 = web.Application() 
app1.router.add_get('/', handle1) 

app2 = web.Application() 
app2.router.add_get('/', handle2) 

ma = MultiApp() 
ma.configure_app(app1, port=8081) 
ma.configure_app(app2, port=8071) 
ma.run_all() 

Als Randbemerkung, einmal darüber nachdenken, warum diese benötigen. In fast allen Fällen ist die Entkopplung die bessere Wahl. Wenn Sie viele Endpunkte im selben Prozess festlegen, sind sie voneinander abhängig. Es gibt einen Fall, der mir in den Sinn kommt und "gute" Argumente hat, den internen Statistik-/Debug-Endpunkt.

1

Obwohl die obige Antwort akzeptiert wurde, hier ist ein anderer Ansatz:

test.py erstellen:

from aiohttp import web 
import asyncio 
import sys 

@asyncio.coroutine 
def status1(request): 
    return web.json_response('App1 OK') 

@asyncio.coroutine 
def status2(request): 
    return web.json_response('App2 OK') 

def start(): 
    try: 
     loop = asyncio.get_event_loop() 

     # App1 
     app1 = web.Application() 
     app1.router.add_get('/status', status1) 
     handler1 = app1.make_handler() 
     coroutine1 = loop.create_server(handler1, '0.0.0.0', 8081) 
     server1 = loop.run_until_complete(coroutine1) 
     address1, port1 = server1.sockets[0].getsockname() 
     print('App1 started on http://{}:{}'.format(address1, port1)) 

     # App2 
     app2 = web.Application() 
     app2.router.add_get('/status', status2) 
     handler2 = app2.make_handler() 
     coroutine2 = loop.create_server(handler2, '0.0.0.0', 8082) 
     server2 = loop.run_until_complete(coroutine2) 
     address2, port2 = server2.sockets[0].getsockname() 
     print('App2 started on http://{}:{}'.format(address2, port2)) 

     try: 
      loop.run_forever() 
     except KeyboardInterrupt: 
      pass 
     finally: 
      server1.close() 
      loop.run_until_complete(app1.shutdown()) 
      loop.run_until_complete(handler1.shutdown(60.0)) 
      loop.run_until_complete(handler1.finish_connections(1.0)) 
      loop.run_until_complete(app1.cleanup()) 

      server2.close() 
      loop.run_until_complete(app2.shutdown()) 
      loop.run_until_complete(handler2.shutdown(60.0)) 
      loop.run_until_complete(handler2.finish_connections(1.0)) 
      loop.run_until_complete(app2.cleanup()) 

     loop.close() 
    except Exception as e: 
     sys.stderr.write('Error: ' + format(str(e)) + "\n") 
     sys.exit(1) 

if __name__ == '__main__': 
    start() 

Am Terminal öffnen zwei Registerkarten. In einer Registerkarte laufen

python test.py 

In anderen Registerkarte laufen

curl -X GET http://localhost:8081/status 
curl -X GET http://localhost:8082/status 

Sie Antwort erhalten

"App1 OK" 
"App2 OK" 
Verwandte Themen