2017-06-30 16 views
6

Có thể hai đối tượng aiohttp.web.Application() đang chạy trong cùng một quá trình, ví dụ: trên các cổng khác nhau?Nhiều ứng dụng aiohttp() đang chạy trong cùng một quá trình?

tôi thấy một loạt các ví dụ về aiohttp mã như:

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) 

Tôi tự hỏi nếu có một số tương đương, nơi nhiều web.Applications() có thể được cấu hình để chạy cùng một lúc. Một cái gì đó như:

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() 

Trường hợp sử dụng của tôi là tôi có một khuôn khổ python web hiện có, và tôi đang tạo mẫu thử tương tự trong python 3.6 với aiohttp.

Tôi hiểu rằng nhiều máy chủ python có thể chạy phía sau ví dụ: nginx (xem thêm http://aiohttp.readthedocs.io/en/stable/deployment.html); đó không phải là những gì tôi theo sau. Tôi muốn khám phá khả năng của hai máy chủ web aiohttp với cùng một vòng lặp sự kiện asyncio, chạy trong cùng một quá trình python, phục vụ trên hai cổng khác nhau.

Trả lời

5

Có, bạn có thể - chỉ cần viết một số trình bao bọc có triển khai lại run_app.

Đây là một ví dụ đơn giản. Tất cả các phần ứng dụng cụ thể của run_app được chuyển đến lớp chuyên dụng AppWrapper. MultiApp chỉ chịu trách nhiệm khởi tạo tất cả các ứng dụng được định cấu hình, tiếp tục chạy vòng lặp và dọn dẹp.

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() 

Note: nhận thức được việc sử dụng các phương pháp nội aiohttp 's, mà có thể bị thay đổi.

Bây giờ chúng ta hãy sử dụng nó:

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() 

Là một mặt lưu ý, hãy nghĩ lại tại sao bạn cần điều này. Trong hầu như tất cả các trường hợp, tách là lựa chọn tốt hơn. Thiết lập nhiều điểm cuối trong cùng một quá trình làm cho chúng phụ thuộc vào nhau. Có một trường hợp xuất hiện trong tâm trí của tôi và có lý do "tốt", điểm cuối/điểm gỡ lỗi nội bộ.

1

Mặc dù câu trả lời ở trên đã được chấp nhận, đây là một cách tiếp cận khác:

Tạo test.py:

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() 

Tại nhà ga, mở hai tab. Trong một tab, chạy

python test.py 

Trong tab khác, chạy

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

Bạn sẽ nhận được phản ứng

"App1 OK" 
"App2 OK" 
Các vấn đề liên quan