Skip to content

Make the platform safe for async by replacing all thread locals with contextvars #38680

@ormsbee

Description

@ormsbee

Motivation

The lack of proper async support in platform has been a constant hindrance for over a decade. It's kept us from being able to use websockets and has forced to:

  1. Use suboptimal polling solutions for things like course import and timed exams.
  2. Caused awkward UX issues like delayed content indexing after import on libraries, for which we need to make hacky workarounds.
  3. Skip features altogether because they are impractical to implement, like real-time notifications in the LMS when using a browser.

This lack of platform capability has also narrowed our vision of what we can do in terms of collaborative tools and group interactions. When we talk about Teams, group projects, or plugin possibilities, there's a whole space of solutions that we write off in advance because we don't have the ability to do real-time updates effectively.

More recently, @regisb's proposed PXC will require the platform to have async capabilities and be served via some ASGI server (likely granian).

Current Status

We currently have a few gaps:

  1. Our platform still uses threading.local in a number of places—something that only isolates that var to the OS thread, not to the overall execution context (i.e. a thread or asyncio task). This must be addressed first.
  2. Our platform uses explicit thread locking in places. I'm not clear about these cases, but each use would need to be investigated.
  3. We would need a new settings file for an ASGI deployment.
  4. Tutor would need to be updated to deploy a new backend for platform that would route and serve ASGI requests.

Scope of work

To make the platform safe to run in async, we should examine all existing uses of threading within openedx-platform and its dependencies and either remove them (if there are safe alternatives), or convert them to use contextvars equivalents instead. Alternatively, we can try to make use of Django's sync_to_async wrapper where it's appropriate.

I'm currently ignoring threading code that only shows up in tests.

Out of Scope

Actually making the ASGI deployment settings and deployment via granian is out of scope for this Epic. This is just about making things safe to be async, as a precursor to that work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No fields configured for Epic.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions