#33573: Add native async support to redis cache backend
-------------------------------------+-------------------------------------
     Reporter:  Christopher Bailey   |                    Owner:  Ahmed
                                     |  Ibrahim
         Type:  New feature          |                   Status:  assigned
    Component:  Core (Cache system)  |                  Version:  dev
     Severity:  Normal               |               Resolution:
     Keywords:                       |             Triage Stage:
                                     |  Someday/Maybe
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Comment (by amirreza):

 hi 🙌🏼
 so after a good amount of time to investigate things, i'm back to talk
 more on the subject
 in this commecnt i'll try to share what an async client would look like in
 django, and leave it to you to decide if this is desired or not


 == so the first problem that needs solving is the
 
[https://github.com/django/django/blob/main/django/core/cache/__init__.py#L61-L64)
 cleaup] discussed in #36047
 since this is a signal receiver and signal receiver can be
 [https://docs.djangoproject.com/en/5.1/topics/signals/#receiver-functions
 async] since django 5, i can see this fixed like this:

 1. add a `is_async` attribute to cache clients, similar to
 [https://github.com/django/django/blob/main/django/utils/deprecation.py#L87-L88
 middlewares]

 2. change the receiver to be async, like this:
 {{{
 async def close_caches(**kwargs):
     # Some caches need to do a cleanup at the end of a request cycle. If
 not
     # implemented in a particular backend cache.close() is a no-op.
     await caches.close_all()
 }}}
 where `close_all()` is as follows:
 {{{
     async def close_all(self):
         for conn in self.all(initialized_only=True):
             if conn.is_async:
                 await conn.aclose()
             else:
                 conn.close()
 }}}



 == second matter in hand is how to design the async cache backend
 i personally suggest that async backend should be in a different class, i
 hope by the end of this comment you'd agree too

 so i would do something like this:

 1. a base class with common functionality
 2. two (less)base classes for sync and async functionality
 3. two redis backends for sync and async

 async methods would have `a` prefixed to their name (even tho there are no
 sync equivelents)
 for two reason:

 1. to be compatible with rest of django
 2. so if someone wants (for whatever reason), they can combine the two
 class and have a backend that supports both

 tho if you allow me to be naughty a bit🫣, i'll define a `__getattr__`
 that only works in the async backend and allows people to access methods
 without the `a`
 i've planned a similar thing with [https://github.com/amirreza8002/django-
 valkey/blob/commands/django_valkey/base.py#L342-L349 django-valkey]
 so both `await cache.aset()` and `await cache.set()` work





 == some things to have in mind:
 ❕the following problems are not essential part of this ticket, an async
 cache backend can exists without these
 even a 3rd-party can handle these issues, i'm only mentioning for refrence

 1. cache middlewares do not accept an async only cache backend
 to solve this we either have to combine the two backends (as discussed
 above) (in this case the async methods won't even be called, it just
 doesn't break),
 or have new middlewares that support async (i like this one, but i guess
 others don't)


 2. if we decide to make an async middleware,
 [https://github.com/django/django/blob/main/django/utils/decorators.py#L124
 make_middleware_decorator] might not be very happy, since it expects sync
 methods, which don't make sense in an async middleware
 i have made an async only option in a [https://github.com/django-utils
 /django-async-
 extensions/blob/main/django_async_extensions/utils/decorators.py#L31 3rd-
 party] before


 3. again if we move for an async middleware,
 
[https://github.com/django/django/blob/main/django/views/decorators/cache.py#L10,
 cache_page] decorator won't work, needs another one


 4. these two caching utils expect a sync backend
 [https://github.com/django/django/blob/main/django/utils/cache.py#L377]
 and
 [https://github.com/django/django/blob/main/django/utils/cache.py#L399]


 5. if cache server is used for sessions,  the session middleware doesn't
 support async operations
 the solutions mentionedfor cache middleware also applies here


 i hope this can give some calrity on how this would work
 as before, i can implement this, if this is a feature that people want,
 and if not, well at least this can be used as refrence for other people

 with best of wishes♥️
-- 
Ticket URL: <https://code.djangoproject.com/ticket/33573#comment:19>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/010701961318afdc-9cd825b1-349c-4c4a-898d-f28c3158066d-000000%40eu-central-1.amazonses.com.

Reply via email to