This came up again in discussion on Discord. Posting a potential solution:
from asyncio import TimeoutError, sleep, wait_for
from functools import wraps
from inspect import isawaitable
from sanic import HTTPResponse, Request, Sanic, json
from sanic.exceptions import ServiceUnavailable
app = Sanic("TestApp")
app.config.RESPONSE_TIMEOUT = 120
def reduced(timeout: int):
def decorator(f):
@wraps(f)
async def decorated_function(request, *args, **kwargs):
response = f(request, *args, **kwargs)
if isawaitable(response):
try:
response = await wait_for(response, timeout)
except TimeoutError:
raise ServiceUnavailable("Response timeout")
return response
return decorated_function
return decorator
async def do_response(pause: int) -> HTTPResponse:
print("Sleeping")
for _ in range(pause):
print("> .")
await sleep(1)
return json({"pause": pause})
@app.get("/regular/<pause:int>")
async def regular_handler(request: Request, pause: int):
return await do_response(pause)
@app.get("/reduced/<pause:int>")
@reduced(5)
async def reduced_handler(request: Request, pause: int):
return await do_response(pause)
Another option is running two apps:
app_regular = Sanic("Regular")
app_extended = Sanic("Extended")
app_extended.config.RESPONSE_TIMEOUT = 120
if __name__ == "__main__":
app_regular.prepare(port=8001)
app_extended.prepare(port=8002)
Sanic.serve()