使用tornado为swagger生成的服务器提供异步端点
我已经使用swagger编辑器生成了一个服务器。然后,我将使用Tornado作为http服务器,如:使用tornado为swagger生成的服务器提供异步端点,swagger,python-asyncio,tornado,Swagger,Python Asyncio,Tornado,我已经使用swagger编辑器生成了一个服务器。然后,我将使用Tornado作为http服务器,如: def main(): app = App(system_manager=system_manager, import_name=__name__, specification_dir='./swagger/', server='tornado') app.app.json_encoder = encoder.JSONEncoder app.a
def main():
app = App(system_manager=system_manager, import_name=__name__,
specification_dir='./swagger/', server='tornado')
app.app.json_encoder = encoder.JSONEncoder
app.add_api('swagger.yaml', arguments={
'title': 'API'}, pythonic_params=True)
app.run(port=8085)
应用程序所在位置:
class App(connexion.App):
def __init__(self, system_manager, import_name, server='tornado', **kwargs):
super(App, self).__init__(import_name, server=server, **kwargs)
if not issubclass(type(system_manager), SystemManager):
raise ValueError(
"App.init: 'system_manager' is not a subclass of 'SystemManager'")
self.__system_manager = system_manager
def run(self, port=None, server=None, debug=None, host=None, **options):
server_type = server or self.server
if server_type != 'tornado':
super(App, self).run(port=port, server=server,
debug=debug, host=host, **options)
return None
if port is not None:
self.port = port
elif self.port is None:
self.port = 5000
self.host = host or self.host or '0.0.0.0'
if server is not None:
self.server = server
if debug is not None:
self.debug = debug
wsgi_container = tornado.wsgi.WSGIContainer(self.app)
http_server = tornado.web.Application([
(r'/websocket/.*', WebSocket, dict(system_manager=self.__system_manager)),
(r'^/v1/wifi(/all)*$', AsyncFallbackHandler,
dict(fallback=wsgi_container)),
(r'.*', tornado.web.FallbackHandler, dict(fallback=wsgi_container))
], websocket_ping_interval=5)
http_server.listen(self.port, address=self.host)
tornado.ioloop.IOLoop.instance().start()
由于某些原因,我有一些端点需要30秒才能响应,而且因为我使用的是WSGIContainer
,所以所有请求都是同步的。这意味着在这些请求之后提交的每个请求都将被处理,直到完成为止。引用文件:
WSGI是一个同步接口,而Tornado的并发模型是
基于单线程异步执行。这意味着
使用Tornado的WSGIContainer运行WSGI应用程序的可伸缩性不如
在多线程WSGI服务器(如gunicorn或
uwsgi
我曾尝试:
WSGIContainer
,但使用的处理程序将使调用异步。没有成功。我得到:RuntimeError:线程“ThreadPoolExecutor-0\u 0”中没有当前事件循环。
ConnexionResponse
。我也不能将ConnexionResponse
写入管道,因为它必须是string/bytes/dict请帮助我找到一种方法,使我的一些端点异步我通过解包ConnexionResponse并设置状态代码,使我的第二个解决方案能够工作。以下是修复后的情况:
async def run_in_executor(self, method, *args):
loop = tornado.ioloop.IOLoop.instance().asyncio_loop
done, pending = await asyncio.wait(
fs=[loop.run_in_executor(None, method, args)],
return_when=asyncio.ALL_COMPLETED
)
result = done.pop().result()
if type(result) is ConnexionResponse:
self.set_status(result.status_code)
return result.body
enc = JSONEncoder()
return enc.encode(result)
class WifiRequestHandler(tornado.web.RequestHandler):
async def get(self, *args, **kwargs):
# await tornado.gen.sleep(20)
ids = self.get_arguments('ids')
method = get_wifi
if self.request.path.startswith('/v1/wifi/all'):
method = get_wifi_all
self.write(await self.run_in_executor(method, ids))
self.set_header('Content-Type', 'application/json')
async def post(self, *args, **kwargs):
logger.info(kwargs)
body = tornado.escape.json_decode(self.request.body)
self.write(await self.run_in_executor(update_wifi, body))
self.set_header('Content-Type', 'application/json')
async def run_in_executor(self, method, *args):
loop = tornado.ioloop.IOLoop.instance().asyncio_loop
done, pending = await asyncio.wait(
fs=[loop.run_in_executor(None, method, args)],
return_when=asyncio.ALL_COMPLETED
)
result = done.pop().result()
if type(result) is ConnexionResponse:
return result
enc = JSONEncoder()
return enc.encode(result)
async def run_in_executor(self, method, *args):
loop = tornado.ioloop.IOLoop.instance().asyncio_loop
done, pending = await asyncio.wait(
fs=[loop.run_in_executor(None, method, args)],
return_when=asyncio.ALL_COMPLETED
)
result = done.pop().result()
if type(result) is ConnexionResponse:
self.set_status(result.status_code)
return result.body
enc = JSONEncoder()
return enc.encode(result)