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