Flask-like “global” request context in Sanic (asyncio)

A Software Engineer passionate about public good projects and making technology to serve society en masse.
Search for a command to run...

A Software Engineer passionate about public good projects and making technology to serve society en masse.
No comments yet. Be the first to comment.
HS (Harmonised System) Codes help classify customs authorities and businesses around the world to ensure appropriate import/export control. This system recursively classifies a product into finer granularity of categories. Figure 1: A simple exercis...
Jan allows you to deploy and run LLMs on your Windows or macOS computer! 16 Gigabytes of memory and a M1 chip was enough for me to run Mistral locally. Now how do you take Jan and use libraries like Langchain? https://jan.ai Local API Server Click ...
My talk at PyCon Thailand 2023 on the security aspects and possible attack vectors of LLM Applications, tailored to both product people and engineers! https://youtu.be/_fvk_Qa5OsM Thank you PyCon TH team!
Looking for a flat for rent, with LLMs
Code generators replace mindless coding with productivity; a pure function that produces predictable code, given a (set of) input(s). Generating boilerplate classes or templates — a common use case for Codegen. Use-case: Generating Classes We will be...
Although something like Flask’s globally accessible request object is considered a terrible way of writing code (explicit is better than implicit), sometimes it makes sense to use it. For example, while passing a Correlation-ID to track a request’s life cycle through your micro-services.
You can memorize the Correlation-ID throughout the lifecycle of a request without explicitly passing it around like juggling balls. This is actually a good approach as the Correlation ID is not a core business logic – just a distraction. We’ll see how we can implement such a request-bound “global” context in Sanic, and how to setup a simple Correlation ID implementation.
This nifty Python module can maintain a distinct context against each asyncio Task. Which means, each request can have an associated context we can use to store and pass around passive details.
$ pip install aiotask-context
from sanic import Sanic
from sanic.response import json
# import aiotask-context
import aiotask_context as context
app = Sanic()
# hook aiotask-context
@app.listener('after_server_start')
async def hook_context(app, loop):
loop.set_task_factory(context.task_factory)
@app.route("/")
async def test(request):
return json({"hello": "world"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Now we have a simple Sanic app with the context hooked up.
Now, let’s grab the correlation ID if it comes with the request, or generate our own otherwise. Afterwards, we need to save that value to the context for future use in other parts of the code (i.e. logging, requests to other microservices and so on).
from uuid import uuid4
import aiotask_context as context
@app.middleware('request')
async def handle_correlation_id(request):
cid = request.headers.get('X-Correlation-ID') or str(uuid4())
context.set('cid', cid)
And throughout the code, if you need the cid or any context value you have set, simply use context.get(key).
And the last step is definitely all about responding with the Correlation ID. We’ll be sticking to the middleware for this too. We just need to update the response object from the context.
@app.middleware('response')
async def insert_correlation_id(request, response):
response.headers["X-Correlation-ID"] = context.get('cid')
Great! Now we don’t have to write spaghetti code and get lost in passing CIDs from functions to functions. Cheers!