Search code examples
djangomultithreadingpython-asynciocoroutinedjango-middleware

how to replace thread_locals logic on async code?


at a django project, i have a lot of code that depends on thread_locals: middlewares using correlation ids, other logic depending on these middlewares, cached info about the request and so on.

recently i started to mix sync code with async, and since i have a single thread serving the async part, i cannot use thread_locals anymore. since i'm using lots of sync_to_async and async_to_sync adapters, i cannot use context vars, because at the same request different coroutines are executed the context is copied accordingly, making contextvars the right replacement for thread_locals

what alternatives do i have to manage short lived information that is unique to each request? i thought about to store everything on a redis as cache, but again, how show i generate/retrieve the key from each request on several points through its execution?


Solution

  • Python has the contextvars lib module to provide some of the functionality of thread-locals to async code. https://docs.python.org/3/library/contextvars.html -

    however, the API for contextvars is not the same - to the contrary, each context_var can only bear a single value, and have to be set and reset by method-calling instead of the = operator.

    I've created a project before contextvars was official which attempts to provide a "context" which works more closely like threadlocals - -if you want to try it, it currently has to be pip-installed directly from git - the major problem being I had no real-world project needing it which took me to go the extra-mile needed to polish it for publication on Pypi -

    Nonetheless, it works flawlessly with all test scenarios I could come up with - the project is at https://github.com/jsbueno/extracontext and can be pip installed with pip install git+https://github.com/jsbueno/[email protected]