# Async Cache, and a helper for porting sync code

**URL:** <https://forum.djangoproject.com/t/async-cache-and-a-helper-for-porting-sync-code/302>\
**Category:** Async\
**Created:** [September 24, 2019, 8:31pm UTC](https://forum.djangoproject.com/t/async-cache-and-a-helper-for-porting-sync-code/302 "2019-09-24T20:31:18Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![nicolaslara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nicolaslara/32/154_2.png) [@nicolaslara](https://forum.djangoproject.com/u/nicolaslara)\
**Post date:** [September 24, 2019, 8:31pm UTC](https://forum.djangoproject.com/t/async-cache-and-a-helper-for-porting-sync-code/302/1 "2019-09-24T20:31:18Z")

</div>

I’ve been working on adding async support to the caching framework. It is still a work in progress, but I think I’m at a point where I can start getting more eyes on it.

# Caching

The actual work to write an async-capable cache backend is actually pretty straightforward, and there are good libraries to make the cache calls asynchronously. The hard part here is API design, **how do we provide users with a clean way to access the cache in both sync and async contexts?**.

I have implemented a backend for memcached in two ways: one based on the current memcached implementation using `sync_to_async` and another based on [aiocache](https://github.com/argaen/aiocache) (which also supports redis and others). This currently works as a proof-of-concept (the code still needs some cleanup) and allows you to call the appropriate sync or async function in the cache framework from either context.

```auto
In [1]: from django.core.cache import cache
In [2]: cache.set('from_sync', 1)
In [3]: await cache.set.as_async('from_async', 2)

In [4]: await cache.get.as_async('from_sync')
Out[4]: 1

In [5]: cache.get('from_async')
Out[5]: 2

In [6]: cache.get.as_sync('from_sync')
Out[6]: 1

In [7]: cache.get.as_async('from_sync')
Out[7]: <coroutine object SyncToAsync. __call__ at 0x1048a0950>

```

## API Design

The suggested API design here is to provide an extension to the critical functions so that users can use `.as_sync` and `.as_async` on them which will provide a function (or method) that behaves the same way as the existing one, but that is adapted to the appropriate calling context.

# Helper decorator

This is all implemented via a helper decorator (currently called `auto_async`) which by default wraps the original function in `sync_to_asyc` or `async_to_sync` as needed and that will allow for custom sync or async implementations to be injected.

## Using the helper to make other parts of django async-capable

The idea behind the helper is to allow us to quickly make other parts of django async-capable as needed. The process would be something like this:

- Wrap code in `auto_async` or `async_unsafe` as needed. This leaves us with a naive implementation that runs the existing code via `sync_to_async`
- Provide an appropriate async version of the code we want to replace. The decorator should make this customization easy (WIP)
- As the implementation of these functions evolve and gets properly tested, we can change the default behaviour to sync or async as needed, and provide deprecation or usage warnings when the functions get created or executed

* * *

The current code can be seen in this pull request: [https://github.com/andrewgodwin/django/pull/6/files](https://github.com/andrewgodwin/django/pull/6/files)

---

<div class="post-metadata">

**Author:** ![andrewgodwin](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrewgodwin/32/2_2.png) [@andrewgodwin](https://forum.djangoproject.com/u/andrewgodwin)\
**Post date:** [September 26, 2019, 5:24pm UTC](https://forum.djangoproject.com/t/async-cache-and-a-helper-for-porting-sync-code/302/2 "2019-09-26T17:24:03Z")

</div>

We discussed this at DjangoCon and agreed that the better approach is

```
cache.get
cache.async.get
cache.sync.get

```

There was some worry about `async` being a reserved word, but it appears to work fine in our syntax testing. @nicolaslara is going to try making an implementation of this and see how it goes.

---

<div class="post-metadata">

**Author:** ![andrewgodwin](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/andrewgodwin/32/2_2.png) [@andrewgodwin](https://forum.djangoproject.com/u/andrewgodwin)\
**Post date:** [September 27, 2019, 12:01am UTC](https://forum.djangoproject.com/t/async-cache-and-a-helper-for-porting-sync-code/302/3 "2019-09-27T00:01:39Z")

</div>

Turns out `async` is a reserved word… on 3.7. Suggestions for an alternate name have been:

- `cache.a.get`
- `cache.as_async.get`

We’re going to try `a` for now and see how it sits.

---

<div class="post-metadata">

**Author:** ![AutumnalDream](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/autumnaldream/32/533_2.png) [@AutumnalDream](https://forum.djangoproject.com/u/AutumnalDream)\
**Post date:** [January 13, 2020, 11:49pm UTC](https://forum.djangoproject.com/t/async-cache-and-a-helper-for-porting-sync-code/302/4 "2020-01-13T23:49:09Z")

</div>

Sorry if this is a dumb question but what’s the benefit of doing the API as `cache.X.get` vs prepending “async\_” like `cache.async_get` or `model.async_objects.all()`?
