简体   繁体   English

Python 问题:无法在单独的线程或事件循环中运行连接 aiohttp 服务器

[英]Python Problems: Unable to run connexion aiohttp server in a separate thread or event loop

I have been unable to get a connexion server using aiohttp into the background so that the main thread isn't hung when I start my webserver.我一直无法使用 aiohttp 在后台获取连接服务器,因此当我启动我的网络服务器时主线程不会挂起。

I think I probably could by using asyncio and create a task for everything else, but I'm writing a library that is going to be reused by other people and companies and I don't have the ability to enforce that kind of design pattern unilaterally and universally.我想我可能可以通过使用 asyncio 并为其他所有内容创建一个任务,但是我正在编写一个将被其他人和公司重用的库,我没有能力单方面执行这种设计模式并且普遍。

I have gotten this working(from https://newbedev.com/how-to-run-an-aiohttp-server-in-a-thread ):我已经得到了这个工作(来自https://newbedev.com/how-to-run-an-aiohttp-server-in-a-thread ):

import asyncio
import threading
from aiohttp import web


def aiohttp_server():
    def say_hello(request):
        return web.Response(text='Hello, world')

    app = web.Application(debug=True)
    app.add_routes([web.get('/', say_hello)])
    handler = app.make_handler()
    return handler


def run_server(handler):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    server = loop.create_server(handler, host='127.0.0.1', port=8089)
    loop.run_until_complete(server)
    loop.run_forever()


t = threading.Thread(target=run_server, args=(aiohttp_server(),))
t.start()

for i in range(50000):
   print('Hi from Main Thread')
   time.sleep(5)

This leaves the server up and running and then allows the main thread to keep going.这使服务器启动并运行,然后允许主线程继续运行。

However, when I try to take this code and make it work with starting up the connexion server using the following code, I can't get things up and running and I'm on day 2 and I have got to get moving.但是,当我尝试使用此代码并使其与使用以下代码启动连接服务器一起工作时,我无法启动并运行它,我已经到了第 2 天,我必须开始行动。 I'm hoping someone sees the dumb thing I've done or misunderstood and can tell me how to fix it.我希望有人看到我做过或误解的愚蠢的事情,并能告诉我如何解决它。

def initializeServerTest():

    app = connexion.AioHttpApp(__name__, 
        port=8080, 
        specification_dir='openAPISpecs/',
        # https://github.com/OpenAPITools/openapi-generator/issues/1322
        only_one_api=True
        )
   
    app.add_api('openAPISpec.json', 
        arguments={'title': 'Instrument and HUB API'}, 
        pythonic_params=True, 
        validate_responses=True
        )

    # Configure default CORS settings.
    cors = aiohttp_cors.setup(app.app, defaults={
            "*": aiohttp_cors.ResourceOptions(allow_credentials=True,
                                            expose_headers="*",
                                            allow_headers="*", 
                                            allow_methods=["GET", "POST", "PUT"]
                                            )
    })

    # Configure CORS on every route
    for route in list(app.app.router.routes()):
        cors.add(route)
    
    # now create a runner we will start later
    runner = web.AppRunner(app.create_app())

    return runner

def run_server(runner):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(runner.setup())
    site = web.TCPSite(runner, 'localhost', 8080)
    loop.run_until_complete(site.start())
    loop.run_forever()

def StartServerInBackground():
    t = threading.Thread(target=run_server, args=(initializeServerTest(),))
    t.start()

When I execute this I get my main thread back, but the web server does not respond to any requests.当我执行此操作时,我会恢复主线程,但 web 服务器不响应任何请求。

Any help would be much appreciated任何帮助将非常感激

Alright, so here was the solution I came up with:好吧,这是我想出的解决方案:

import connexion
from aiohttp import web
from aiohttp_cors
import threading

app = {}
apprunner = {}

def _initializeServer():

    # use module level app
    global app

    app = connexion.AioHttpApp(__name__, 
        port=8080, 
        specification_dir='openAPISpecs/',
        # https://github.com/OpenAPITools/openapi-generator/issues/1322
        only_one_api=True
        )

    app.add_api('openAPISpec.json', 
        arguments={'title': 'Analyzer and HUB API'}, 
        pythonic_params=True, 
        validate_responses=True,
        # doesn't always work with JSON bodies: https://github.com/zalando/connexion/issues/837
        strict_validation=True
        )

    # Configure default CORS settings.
    cors = aiohttp_cors.setup(app.app, defaults={
            "*": aiohttp_cors.ResourceOptions(allow_credentials=True,
                                            expose_headers="*",
                                            allow_headers="*", 
                                            allow_methods=["GET", "POST", "PUT", "DELETE"]
                                        )
    })

    # Configure CORS on every route
    for route in list(app.app.router.routes()):
        cors.add(route)

def _startServer_NonBlocking(runner):
    #store runner at module level for use later
    global apprunner
    apprunner = runner

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(runner.setup())

    site = web.TCPSite(runner, 'localhost', 8080)
    loop.run_until_complete(site.start())
    loop.run_forever()

def startServer_NonBlocking():
    # grab module level serverRunning for comparison in next line
    global serverRunning

    # if the server isn't already running
    if(serverRunning == False):
        # configure new thread and start it
        newThread = threading.Thread(target=_startServer_NonBlocking, args=(_initializeServer_NonBlocking(),))
        newThread.start()

        # set flag that the server is running so we don't ever try to start it again
        serverRunning = True

The secret sauce was in finding that you had to use app.app to get the runner and then you could use that later on to do the setup per the cookbook on the connexion documentation.秘诀在于发现你必须使用 app.app 来获取跑步者,然后你可以稍后使用它来按照连接文档上的食谱进行设置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM