Это кажется возможным, потому что в app.Sanic.handle_request()
есть этот фрагмент:
if isawaitable(response):
response = await response
А вот как awaitable
проверяется Python:
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)
, если это возможно.
Пробовал решение Михаила, вот что заметил:
raise500
входит вasyncio.sleep()
ret500
не входит вasyncio.sleep()
(баг)raise500
блокирует другиеraise500
(баг)raise500
не блокируетret500
- Не могу сказать, будет ли
ret500
блокировать другиеret500
, потому что это слишком быстро (не спит)
Полный код (запустить, сохранив как test.py
, затем в оболочке 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()