Django atomic increase with initial value
Asked Answered
L

2

6

I'm trying to have atomic increase-or-create operation in Django cache. I'm using memcache as backend. Memcache client's incr_async() function takes initial_value parameter. The meaning is:

If the key does not yet exist in the cache and you specify an initial_value, the key's value will be set to this initial value and then incremented.

However, I don't see how can I do this in Django, as cache.incr() documentation says:

A ValueError will be raised if you attempt to increment or decrement a nonexistent cache key.

Of course I could do:

cache.add(key,initial_value)
cache.incr(key)

But that is not atomic and may lead to race conditions.

Is there a way around this, which would preserve atomicity of the operation?

Limoges answered 18/11, 2011 at 16:30 Comment(2)
See this very similar question: #7967977. One answer suggest that the python implementation of memcache doesn't actually support incr with an inital fallback. You must add and then incr in two separate operations according to that user. You might want to check into the validity of that.Misconception
I understand that it will make things simpler to code, but why not initialize the value when the object logically starts existing somewhere else and then increment at the part of the workflow where you are sure it exists?Theodolite
C
4

As far as I know Django's cache API don't support this. You would have to drop down to the memcache API and do this directly:

from django.core.cache import cache

client = cache._client  # <--direct reference to memcached.Client object
Chitkara answered 18/11, 2011 at 16:34 Comment(4)
is there an easy way to get memcache from Django's cache instance?Limoges
I'm pretty sure. I'll check on how once I get to work in an hour or soChitkara
I think it's just memcache = get_cache('memcache') and then memcache._cache.whatever() (from django.core.cache import get_cache)Misconception
Following newer documentation (e.g. docs.djangoproject.com/en/3.2/topics/cache), there are now .incr(key) and .decr(key) that are atomic if the backend supports it. Most notably, this is supported by Memcached.Counterproposal
C
0

Django cache.add method itself is atomic. Meaning if the key already exists, it won't do anything. So you can use

cache.add(key,initial_value)
cache.incr(key)

without worrying about the race around condition.

Note: Django version 3.0.8

Cobol answered 29/5, 2022 at 13:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.