【发布时间】:2018-05-08 04:24:17
【问题描述】:
这似乎是可能的,因为在app.Sanic.handle_request() 中有这个snippet:
if isawaitable(response):
response = await response
这就是 Python 检查awaitable 的方式:
def isawaitable(object):
"""Return true if object can be passed to an ``await`` expression."""
return (isinstance(object, types.CoroutineType) or
isinstance(object, types.GeneratorType) and
bool(object.gi_code.co_flags & CO_ITERABLE_COROUTINE) or
isinstance(object, collections.abc.Awaitable))
我知道使用async def 创建一个可等待的函数,但我不知道如何创建一个可等待的HTTPResponse 实例。如果可能的话,用简单的await asyncio.sleep(5) 查看可等待响应的示例真的很有帮助。
尝试了 Mikhail 的解决方案,这是我观察到的:
-
raise500进入asyncio.sleep() -
ret500不进入asyncio.sleep()(错误) -
raise500阻止其他raise500(错误) -
raise500不会阻止ret500 - 无法判断
ret500是否会阻止其他ret500,因为它太快(不休眠)
完整代码(保存为test.py,然后在shell中python test.py并转到http://127.0.0.1:8000/api/test运行):
import asyncio
from sanic import Sanic
from sanic.response import HTTPResponse
from sanic.handlers import ErrorHandler
class AsyncHTTPResponse(HTTPResponse): # make it awaitable
def __await__(self):
return self._coro().__await__() # see https://stackoverflow.com/a/33420721/1113207
async def _coro(self):
print('Sleeping')
await asyncio.sleep(5)
print('Slept 5 seconds')
return self
class CustomErrorHandler(ErrorHandler):
def response(self, request, exception):
return AsyncHTTPResponse(status=500)
app = Sanic(__name__, error_handler=CustomErrorHandler())
@app.get("/api/test")
async def test(request):
return HTTPResponse(status=204)
@app.get("/api/raise500")
async def raise500(request):
raise Exception
@app.get("/api/ret500")
async def ret500(request):
return AsyncHTTPResponse(status=500)
if __name__ == "__main__":
app.run()
【问题讨论】:
标签: python-asyncio sanic