Async & Concurrency¶
Keywords: async await, concurrent queries, async database, asgi wsgi concurrency
Asok supports dual-core ASGI/WSGI operation. This allows you to deploy Asok applications under ASGI servers (like Uvicorn) for high-concurrency workloads, while maintaining 100% backward compatibility with traditional WSGI deployments (like Gunicorn).
Additionally, Asok supports async def page controllers, asynchronous middlewares, and non-blocking asynchronous ORM operations.
Installation¶
Asynchronous capabilities are optional to keep the core framework lightweight and dependency-free. To install Asok with ASGI support, run:
pip install "asok[async]"
This installs:
uvicorn— A lightning-fast ASGI server.
Running with Uvicorn (ASGI)¶
To start the development server using the ASGI interface rather than the default WSGI server, run:
uvicorn wsgi:app --reload
In production, you can deploy your application with:
uvicorn wsgi:app --host 0.0.0.0 --port 8000 --workers 4
Async Page Controllers¶
You can write standard synchronous controllers or asynchronous async def page controllers. Asok automatically detects if the controller is a coroutine function and handles it appropriately.
# src/pages/users/page.py
from models.user import User
async def get(request):
# Perform non-blocking database query
users = await User.all_async()
return request.html("page.html", users=users)
Async Middleware¶
Middleware functions can also be declared using async def. When running under an ASGI server, the middleware will be awaited correctly.
# src/middlewares/02_async_logger.py
import time
async def handle(request, next):
start = time.time()
# Propagate to next middleware/handler asynchronously
response = await next(request)
duration = (time.time() - start) * 1000
print(f"[{request.method}] {request.path} completed in {duration:.2f}ms (async)")
return response
Sync-Async Middleware Interoperability¶
Asok automatically handles mixed chains where some middlewares are synchronous (def) and others are asynchronous (async def).
Under ASGI, synchronous middlewares are wrapped so they run on worker threads without blocking the event loop.
Under WSGI, asynchronous middlewares/controllers are run to completion using an internal event loop wrapper.
Asynchronous ORM Operations¶
Asok Models expose async variants of all standard querying and saving methods.
Synchronous Method |
Asynchronous Equivalent |
Description |
|---|---|---|
|
|
Retrieve all records from the database |
|
|
Find a single record by field criteria |
|
|
Instantiates and saves a new record |
|
|
Saves updates to an existing model instance |
|
|
Deletes the model instance from the database |
Example usage:¶
# src/pages/profile/page.py
from models.user import User
async def get(request):
user_id = request.query.get("id")
# Non-blocking find
user = await User.find_async(id=user_id)
if not user:
request.status(404)
return "User not found"
return request.html("page.html", user=user)
async def post(request):
name = request.form.get("name")
# Non-blocking save
user = await User.create_async(name=name, email="new@example.com")
return request.redirect(f"/profile?id={user.id}")
Under the Hood¶
The *_async ORM methods run database operations on a thread pool (via asyncio.to_thread) to guarantee compatibility with all supported database engines (SQLite, PostgreSQL, and MySQL) without duplicating the underlying driver-specific queries.