granian
granian copied to clipboard
Implement a timeout
Something like --timeout 30
, I'm writing a benchmark and I need to set this value
🤔 a timeout on what? can you be more specific? Also, if I'd implementing a benchmark, and we're talking about a timeout on request time, I'd implement it on the client side, not on the server. Having a timeout on the server would produce false results in a benchmark IMHO.
For handling the requests timeouts, I have something like
echo "# Django Workers" > $FILE
sudo fuser -k $PORT/tcp
gunicorn mysite.asgi --timeout $TIMEOUT --workers $THREADS --worker-class uvicorn.workers.UvicornWorker & echo "starting server..."
sleep $SLEEP_TIME
echo "## ASGI Gunicorn Uvicorn" >> $FILE
bench
sudo fuser -k $PORT/tcp
granian --interface asgi mysite.asgi:application --port $PORT --workers $THREADS --loop asyncio & echo "starting server..."
sleep $SLEEP_TIME
echo "## Granian Asyncio" >> $FILE
bench
sudo fuser -k $PORT/tcp
granian --interface asgi mysite.asgi:application --port $PORT --workers $THREADS --loop uvloop & echo "starting server..."
sleep $SLEEP_TIME
echo "## Granian uvloop" >> $FILE
bench
sudo fuser -k $PORT/tcp
And I thought if each server would have different timeout it should affect the results, and I'm working over Heroku, it has a request timeout of 30 seconds
My benchmark is not so realistic, I think but cover a lot of common tasks
- benchmark: https://github.com/breatheco-de/apiv2/blob/main/benchmarks/django-workers/bench.sh
- urls: https://github.com/breatheco-de/apiv2/blob/main/benchmarks/django-workers/mysite/urls.py
- views: https://github.com/breatheco-de/apiv2/blob/main/benchmarks/django-workers/myapp/views.py
I got good results, but I could not get any good results for AIOHTTP or HTTPX test, so I think maybe the default request timeout should affect to Granian result
And it appears even with --no-opt
, apparently it is not handling the requests timeout, and it should penalize the results for all the output it is generating in the console
[WARNING] Application callable raised an exception
Task exception was never retrieved
future: <Task finished name='Task-55077' coro=<future_watcher_wrapper.<locals>.future_watcher() done, defined at /home/jefer/dev/work/apiv2/benchmarks/django-workers/.venv/lib/python3.11/site-packages/granian/_futures.py:2> exception=TypeError('PyFutureAwaitable.cancel() takes no arguments (1 given)')>
Traceback (most recent call last):
File "/home/jefer/dev/work/apiv2/benchmarks/django-workers/.venv/lib/python3.11/site-packages/granian/_futures.py", line 4, in future_watcher
await inner(watcher.scope, watcher.proto)
File "/home/jefer/dev/work/apiv2/benchmarks/django-workers/.venv/lib/python3.11/site-packages/django/core/handlers/asgi.py", line 170, in __call__
await self.handle(scope, receive, send)
File "/home/jefer/dev/work/apiv2/benchmarks/django-workers/.venv/lib/python3.11/site-packages/django/core/handlers/asgi.py", line 218, in handle
task.cancel()
TypeError: PyFutureAwaitable.cancel() takes no arguments (1 given)
Task exception was never retrieved
future: <Task finished name='Task-55434' coro=<ASGIHandler.listen_for_disconnect() done, defined at /home/jefer/dev/work/apiv2/benchmarks/django-workers/.venv/lib/python3.11/site-packages/django/core/handlers/asgi.py:226> exception=RequestAborted()>
Traceback (most recent call last):
File "/home/jefer/dev/work/apiv2/benchmarks/django-workers/.venv/lib/python3.11/site-packages/django/core/handlers/asgi.py", line 230, in listen_for_disconnect
raise RequestAborted()
django.core.exceptions.RequestAborted
@jefer94 1.0 added the proper code to handle cancel
calls on PyFutureAwaitable
, this should solve your issue.
As for the timeout thing, I'm still not convinced Granian should implement this and leave it to the application/framework.
I will make an endpoint in Heroku with an asyncio.sleep(40); print('somebody')
on Wednesday to see how them interact
A timeout would be nice, timeout with the proxy, nging or whatever, just like unicorn and gunicorn