# 🦄 Tsuno
**High-performance WSGI/ASGI server powered by Rust**



Tsuno aims to be a drop-in replacement for Gunicorn and Uvicorn with a Rust-powered transport layer. Run your [Django](https://www.djangoproject.com/), [Flask](https://flask.palletsprojects.com/), [FastAPI](https://fastapi.tiangolo.com/), [Starlette](https://www.starlette.io/), and [connect-python](https://github.com/connectrpc/connect-python) applications with HTTP/2 support.
## Installation
```bash
pip install tsuno
```
## Quick Start
### Command Line
```bash
tsuno myapp:app --workers 4 --bind 0.0.0.0:8000
```
### Python API
**Flask (WSGI)**:
```python
from flask import Flask
from tsuno import run
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello World"
if __name__ == "__main__":
run(app)
```
**FastAPI (ASGI)**:
```python
from fastapi import FastAPI
from tsuno import run
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
if __name__ == "__main__":
run(app)
```
See [`examples/`](examples/) for complete working examples.
## What Makes Tsuno Different
- **Mixed Protocol Serving**: Serve WSGI and ASGI apps simultaneously on the same server ([example](examples/mixed_wsgi_asgi.py))
- **High Performance**: Powered by Tokio and hyper
- **Complete API Compatibility**: Drop-in replacement for both Gunicorn AND Uvicorn as much as possible
- **Unix Domain Sockets**: Full UDS support for nginx integration ([example](examples/uds_example.py))
## Examples
Complete working examples in the [`examples/`](examples/) directory:
| Example | Description |
|---------|-------------|
| **[wsgi_flask_app.py](examples/wsgi_flask_app.py)** | Flask WSGI application |
| **[asgi_fastapi_app.py](examples/asgi_fastapi_app.py)** | FastAPI ASGI application |
| **[mixed_wsgi_asgi.py](examples/mixed_wsgi_asgi.py)** | **Mixed WSGI + ASGI serving** (unique to Tsuno!) |
| **[wsgi_multi_app.py](examples/wsgi_multi_app.py)** | Multiple Flask apps on different paths |
| **[asgi_multi_app.py](examples/asgi_multi_app.py)** | Multiple FastAPI apps on different paths |
| **[uds_example.py](examples/uds_example.py)** | Unix Domain Socket server |
| **[lifespan_test.py](examples/lifespan_test.py)** | ASGI Lifespan events demo |
| **[tsuno.toml](examples/tsuno.toml)** | TOML configuration example |
## Configuration
### Command Line
```bash
# Basic
tsuno myapp:app --bind 0.0.0.0:8000 --workers 4
# With auto-reload (development)
tsuno myapp:app --reload
# With Unix domain socket
tsuno myapp:app --uds /tmp/tsuno.sock
# With configuration file
tsuno myapp:app -c tsuno.toml
```
### Configuration File
**Python format** (Gunicorn-compatible):
```python
# tsuno.conf.py
bind = "0.0.0.0:8000"
workers = 4
threads = 2
log_level = "info"
```
**TOML format**:
```toml
# tsuno.toml
bind = "0.0.0.0:8000"
workers = 4
threads = 2
log_level = "info"
```
See [examples/tsuno.toml](examples/tsuno.toml) for all options.
### Python API
```python
from tsuno import run
run(
app,
host="0.0.0.0",
port=8000,
workers=4,
reload=True, # Development only
)
```
## Production Features
### Worker Management
- Auto-restart crashed workers
- Graceful shutdown and reload
- Worker timeout monitoring
- Max requests per worker (memory leak prevention)
### Graceful Reload (Zero-Downtime)
```bash
# Start with PID file
tsuno myapp:app --pid /var/run/tsuno.pid
# Graceful reload (no downtime)
kill -HUP $(cat /var/run/tsuno.pid)
```
### Logging
- Structured logging (text/JSON)
- Access log support
- Customizable log formats
## Performance
Performance varies by workload, platform, and configuration.
Run `wrk` or `h2load` benchmarks to measure performance on your specific hardware.
## Migration
### From Gunicorn
```bash
# Before
gunicorn myapp:app --workers 4 --bind 0.0.0.0:8000
# After (same syntax!)
tsuno myapp:app --workers 4 --bind 0.0.0.0:8000
```
### From Uvicorn
```python
# Before
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000, workers=4)
# After (compatible API!)
import tsuno
tsuno.run(app, host="0.0.0.0", port=8000, workers=4)
```
## Development Status
**Tsuno is in early development (alpha stage)**.
- ⚠️ Real-world production testing needed
**Help us test!** Report issues at [github.com/i2y/tsuno/issues](https://github.com/i2y/tsuno/issues)
## Requirements
- Python 3.11 or later
- Rust toolchain (for building from source)
## License
MIT License - see [LICENSE](LICENSE)
## Links
- **Repository**: [github.com/i2y/tsuno](https://github.com/i2y/tsuno)
- **Issues**: [github.com/i2y/tsuno/issues](https://github.com/i2y/tsuno/issues)
## Acknowledgments
Tsuno is inspired by and builds upon excellent work from:
- **Gunicorn** & **Uvicorn**: Server standards
- **Granian**: Rust-Python hybrid architecture
- **Tokio**, **hyper**, **PyO3**: Rust ecosystem
Raw data
{
"_id": null,
"home_page": null,
"name": "tsuno",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "wsgi, asgi, server, rust, async, http2, fastapi, flask, django, starlette, tsuno",
"author": null,
"author_email": "i2y <>",
"download_url": "https://files.pythonhosted.org/packages/b8/fe/42ea560d3781020c60ee3ed8a898a05fefec49bb063f487eb2c1fe7a7504/tsuno-0.1.2.tar.gz",
"platform": null,
"description": "# \ud83e\udd84 Tsuno\n\n**High-performance WSGI/ASGI server powered by Rust**\n\n\n\n\n\nTsuno aims to be a drop-in replacement for Gunicorn and Uvicorn with a Rust-powered transport layer. Run your [Django](https://www.djangoproject.com/), [Flask](https://flask.palletsprojects.com/), [FastAPI](https://fastapi.tiangolo.com/), [Starlette](https://www.starlette.io/), and [connect-python](https://github.com/connectrpc/connect-python) applications with HTTP/2 support.\n\n## Installation\n\n```bash\npip install tsuno\n```\n\n## Quick Start\n\n### Command Line\n\n```bash\ntsuno myapp:app --workers 4 --bind 0.0.0.0:8000\n```\n\n### Python API\n\n**Flask (WSGI)**:\n```python\nfrom flask import Flask\nfrom tsuno import run\n\napp = Flask(__name__)\n\n@app.route(\"/\")\ndef hello():\n return \"Hello World\"\n\nif __name__ == \"__main__\":\n run(app)\n```\n\n**FastAPI (ASGI)**:\n```python\nfrom fastapi import FastAPI\nfrom tsuno import run\n\napp = FastAPI()\n\n@app.get(\"/\")\nasync def root():\n return {\"message\": \"Hello World\"}\n\nif __name__ == \"__main__\":\n run(app)\n```\n\nSee [`examples/`](examples/) for complete working examples.\n\n## What Makes Tsuno Different\n\n- **Mixed Protocol Serving**: Serve WSGI and ASGI apps simultaneously on the same server ([example](examples/mixed_wsgi_asgi.py))\n- **High Performance**: Powered by Tokio and hyper\n- **Complete API Compatibility**: Drop-in replacement for both Gunicorn AND Uvicorn as much as possible\n- **Unix Domain Sockets**: Full UDS support for nginx integration ([example](examples/uds_example.py))\n\n## Examples\n\nComplete working examples in the [`examples/`](examples/) directory:\n\n| Example | Description |\n|---------|-------------|\n| **[wsgi_flask_app.py](examples/wsgi_flask_app.py)** | Flask WSGI application |\n| **[asgi_fastapi_app.py](examples/asgi_fastapi_app.py)** | FastAPI ASGI application |\n| **[mixed_wsgi_asgi.py](examples/mixed_wsgi_asgi.py)** | **Mixed WSGI + ASGI serving** (unique to Tsuno!) |\n| **[wsgi_multi_app.py](examples/wsgi_multi_app.py)** | Multiple Flask apps on different paths |\n| **[asgi_multi_app.py](examples/asgi_multi_app.py)** | Multiple FastAPI apps on different paths |\n| **[uds_example.py](examples/uds_example.py)** | Unix Domain Socket server |\n| **[lifespan_test.py](examples/lifespan_test.py)** | ASGI Lifespan events demo |\n| **[tsuno.toml](examples/tsuno.toml)** | TOML configuration example |\n\n## Configuration\n\n### Command Line\n\n```bash\n# Basic\ntsuno myapp:app --bind 0.0.0.0:8000 --workers 4\n\n# With auto-reload (development)\ntsuno myapp:app --reload\n\n# With Unix domain socket\ntsuno myapp:app --uds /tmp/tsuno.sock\n\n# With configuration file\ntsuno myapp:app -c tsuno.toml\n```\n\n### Configuration File\n\n**Python format** (Gunicorn-compatible):\n```python\n# tsuno.conf.py\nbind = \"0.0.0.0:8000\"\nworkers = 4\nthreads = 2\nlog_level = \"info\"\n```\n\n**TOML format**:\n```toml\n# tsuno.toml\nbind = \"0.0.0.0:8000\"\nworkers = 4\nthreads = 2\nlog_level = \"info\"\n```\n\nSee [examples/tsuno.toml](examples/tsuno.toml) for all options.\n\n### Python API\n\n```python\nfrom tsuno import run\n\nrun(\n app,\n host=\"0.0.0.0\",\n port=8000,\n workers=4,\n reload=True, # Development only\n)\n```\n\n## Production Features\n\n### Worker Management\n- Auto-restart crashed workers\n- Graceful shutdown and reload\n- Worker timeout monitoring\n- Max requests per worker (memory leak prevention)\n\n### Graceful Reload (Zero-Downtime)\n\n```bash\n# Start with PID file\ntsuno myapp:app --pid /var/run/tsuno.pid\n\n# Graceful reload (no downtime)\nkill -HUP $(cat /var/run/tsuno.pid)\n```\n\n### Logging\n- Structured logging (text/JSON)\n- Access log support\n- Customizable log formats\n\n## Performance\n\nPerformance varies by workload, platform, and configuration.\nRun `wrk` or `h2load` benchmarks to measure performance on your specific hardware.\n\n## Migration\n\n### From Gunicorn\n\n```bash\n# Before\ngunicorn myapp:app --workers 4 --bind 0.0.0.0:8000\n\n# After (same syntax!)\ntsuno myapp:app --workers 4 --bind 0.0.0.0:8000\n```\n\n### From Uvicorn\n\n```python\n# Before\nimport uvicorn\nuvicorn.run(app, host=\"0.0.0.0\", port=8000, workers=4)\n\n# After (compatible API!)\nimport tsuno\ntsuno.run(app, host=\"0.0.0.0\", port=8000, workers=4)\n```\n\n## Development Status\n\n**Tsuno is in early development (alpha stage)**.\n\n- \u26a0\ufe0f Real-world production testing needed\n\n**Help us test!** Report issues at [github.com/i2y/tsuno/issues](https://github.com/i2y/tsuno/issues)\n\n## Requirements\n\n- Python 3.11 or later\n- Rust toolchain (for building from source)\n\n## License\n\nMIT License - see [LICENSE](LICENSE)\n\n## Links\n\n- **Repository**: [github.com/i2y/tsuno](https://github.com/i2y/tsuno)\n- **Issues**: [github.com/i2y/tsuno/issues](https://github.com/i2y/tsuno/issues)\n\n## Acknowledgments\n\nTsuno is inspired by and builds upon excellent work from:\n- **Gunicorn** & **Uvicorn**: Server standards\n- **Granian**: Rust-Python hybrid architecture\n- **Tokio**, **hyper**, **PyO3**: Rust ecosystem\n\n",
"bugtrack_url": null,
"license": null,
"summary": "High-performance WSGI/ASGI server for Python, powered by Rust",
"version": "0.1.2",
"project_urls": {
"Homepage": "https://github.com/i2y/tsuno",
"Issues": "https://github.com/i2y/tsuno/issues",
"Repository": "https://github.com/i2y/tsuno"
},
"split_keywords": [
"wsgi",
" asgi",
" server",
" rust",
" async",
" http2",
" fastapi",
" flask",
" django",
" starlette",
" tsuno"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "dbea09f3305faa90fbd72a81162da102eccbafa9987acd27144a0a8bd294dd23",
"md5": "78858c31c6f99b4952185d4c76b03b76",
"sha256": "68570f8a4d6c8c7f4967b3c4dcc8a92eb5985b7397c2a3fdf1729cc4e0bf7cd9"
},
"downloads": -1,
"filename": "tsuno-0.1.2-cp311-abi3-macosx_11_0_arm64.whl",
"has_sig": false,
"md5_digest": "78858c31c6f99b4952185d4c76b03b76",
"packagetype": "bdist_wheel",
"python_version": "cp311",
"requires_python": ">=3.11",
"size": 1010424,
"upload_time": "2025-10-21T11:35:03",
"upload_time_iso_8601": "2025-10-21T11:35:03.659555Z",
"url": "https://files.pythonhosted.org/packages/db/ea/09f3305faa90fbd72a81162da102eccbafa9987acd27144a0a8bd294dd23/tsuno-0.1.2-cp311-abi3-macosx_11_0_arm64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "69a7d8e3644a79f6a48cfdfdf81c807168e712e08d0086cfb4fbb60f23a1867b",
"md5": "ee418c87fce2da94170f94050c9d59bb",
"sha256": "f3b35086691e7168e0ade28a658f5e12e9ea54b022d46101876fec10d8947399"
},
"downloads": -1,
"filename": "tsuno-0.1.2-cp311-abi3-manylinux_2_28_aarch64.whl",
"has_sig": false,
"md5_digest": "ee418c87fce2da94170f94050c9d59bb",
"packagetype": "bdist_wheel",
"python_version": "cp311",
"requires_python": ">=3.11",
"size": 1082857,
"upload_time": "2025-10-21T11:35:05",
"upload_time_iso_8601": "2025-10-21T11:35:05.315032Z",
"url": "https://files.pythonhosted.org/packages/69/a7/d8e3644a79f6a48cfdfdf81c807168e712e08d0086cfb4fbb60f23a1867b/tsuno-0.1.2-cp311-abi3-manylinux_2_28_aarch64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "54d0fbf3679e5a55508201eb260db017c236fbd221e52f3da0e11ec9e4ecaf6d",
"md5": "c801ef9333c7d9306fc433290a84ef63",
"sha256": "51378d3c454a3d7fc155b5ca033ec94971eb0bde8a1ed5f9a58af4600f31eac7"
},
"downloads": -1,
"filename": "tsuno-0.1.2-cp311-abi3-manylinux_2_28_x86_64.whl",
"has_sig": false,
"md5_digest": "c801ef9333c7d9306fc433290a84ef63",
"packagetype": "bdist_wheel",
"python_version": "cp311",
"requires_python": ">=3.11",
"size": 1163730,
"upload_time": "2025-10-21T11:35:06",
"upload_time_iso_8601": "2025-10-21T11:35:06.615841Z",
"url": "https://files.pythonhosted.org/packages/54/d0/fbf3679e5a55508201eb260db017c236fbd221e52f3da0e11ec9e4ecaf6d/tsuno-0.1.2-cp311-abi3-manylinux_2_28_x86_64.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "b8fe42ea560d3781020c60ee3ed8a898a05fefec49bb063f487eb2c1fe7a7504",
"md5": "44ac9b5f190e563cee65c0edfdd67b3b",
"sha256": "e94a7014b2bca2c466fd9815cb8d06b1ce8a9c0faa5780541b83e3092ca531ea"
},
"downloads": -1,
"filename": "tsuno-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "44ac9b5f190e563cee65c0edfdd67b3b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 63451,
"upload_time": "2025-10-21T11:35:08",
"upload_time_iso_8601": "2025-10-21T11:35:08.564512Z",
"url": "https://files.pythonhosted.org/packages/b8/fe/42ea560d3781020c60ee3ed8a898a05fefec49bb063f487eb2c1fe7a7504/tsuno-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-21 11:35:08",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "i2y",
"github_project": "tsuno",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "tsuno"
}