Hypercorn
Hypercorn is an ASGI and WSGI web server based on Hyper libraries and inspired by Gunicorn. It supports HTTP/1, HTTP/2, WebSockets (over HTTP/1 and HTTP/2), ASGI/2, and ASGI/3 specifications, and can utilize asyncio, uvloop, or trio worker types. Currently at version 0.18.0, Hypercorn is actively maintained with regular updates and focuses on robust protocol support.
Warnings
- breaking Hypercorn dropped support for ASGI/2 and now requires ASGI/3 applications. Applications built against older ASGI/2 specifications will need to be updated.
- deprecated The command-line arguments `--access-log` and `--error-log` have been deprecated in favor of `--access-logfile` and `--error-logfile` for consistency with Gunicorn's logging settings.
- gotcha When running Hypercorn with the `--reload` option inside Docker containers, changes to files mounted via Docker volumes may not trigger a reload as expected.
- gotcha Some users have reported higher-than-expected memory usage or potential memory leaks, particularly in resource-constrained environments like serverless platforms. While improvements have been made, monitoring memory is recommended.
- gotcha There have been reports of Hypercorn not gracefully closing pending connections on `CTRL+C` or when shutting down without explicit worker management (e.g., `--workers 0`), potentially leading to HTTP 503 errors on clients.
Install
-
pip install hypercorn -
pip install 'hypercorn[h3]' -
pip install 'hypercorn[uvloop]'
Imports
- Config
from hypercorn.config import Config
- serve (asyncio)
from hypercorn.asyncio import serve
- serve (trio)
from hypercorn.trio import serve
- run
from hypercorn.run import run
Quickstart
import asyncio
from hypercorn.config import Config
from hypercorn.asyncio import serve
async def app(scope, receive, send):
assert scope['type'] == 'http'
response_body = b'Hello, world!'
headers = [
(b'content-type', b'text/plain'),
(b'content-length', str(len(response_body)).encode())
]
await send({'type': 'http.response.start', 'status': 200, 'headers': headers})
await send({'type': 'http.response.body', 'body': response_body})
async def main():
config = Config()
config.bind = [f"0.0.0.0:{os.environ.get('PORT', '8000')}"]
print(f"Serving on {config.bind[0]}...")
await serve(app, config)
if __name__ == '__main__':
import os
asyncio.run(main())