-
Notifications
You must be signed in to change notification settings - Fork 48
Closed
Description
Python 3.7
dogpile 0.9.0
redis 3.4.1
The redis backend ends up using the redis Lock object to create distributed locks.
Note that by default Redis' Lock objects use thread locals to store locking tokens.
But if a region is configured to use async creation runners, then the lock that's passed to the background thread will not be able to release the lock because the thread local token doesn't exist.
Perhaps lock creation should pass an additional param to signify the lock will be shared across threads? Or a custom Redis lock that wraps the main one to handle this. Yet another option is to have dogpile itself deal with the lock code (thus within the same thread as the lock's creation).
Minimal example:
#!/usr/bin/env python3
from concurrent.futures import ThreadPoolExecutor
from dogpile.cache import make_region
import logging
import time
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
log = logging.getLogger(__name__)
pool = ThreadPoolExecutor(max_workers=1)
def asyncer(cache, key, creator, mutex):
def _call():
log.info("async creator")
try:
value = creator()
cache.set(key, value)
finally:
try:
mutex.release()
except Exception:
log.exception("uhoh")
return pool.submit(_call)
cache = make_region(async_creation_runner=asyncer)
cache.configure(
"dogpile.cache.redis",
expiration_time=2,
arguments={
# Local redis instance in Docker
"url": "redis://redis:6379",
"distributed_lock": True,
"lock_timeout": 0.1,
},
)
@cache.cache_on_arguments()
def doubler(x):
log.info("recompute: %s", x)
return 2 * x
log.info(doubler(4))
time.sleep(3)
log.info(doubler(4))DEBUG:dogpile.cache.region:No value present for key: '__main__:doubler|4'
DEBUG:dogpile.lock:NeedRegenerationException
DEBUG:dogpile.lock:no value, waiting for create lock
DEBUG:dogpile.lock:value creation lock <redis.lock.Lock object at 0x7f857abc4c18> acquired
DEBUG:dogpile.cache.region:No value present for key: '__main__:doubler|4'
DEBUG:dogpile.lock:Calling creation function for not-yet-present value
INFO:__main__:recompute: 4
DEBUG:dogpile.cache.region:Cache value generated in 0.000 seconds for key(s): '__main__:doubler|4'
DEBUG:dogpile.lock:Released creation lock
INFO:__main__:8
DEBUG:dogpile.lock:value creation lock <redis.lock.Lock object at 0x7f857abc4c18> acquired
DEBUG:dogpile.lock:Passing creation lock to async runner
INFO:__main__:async creator
INFO:__main__:recompute: 4
INFO:__main__:8
ERROR:__main__:uhoh
Traceback (most recent call last):
File "./code.py", line 20, in _call
mutex.release()
File "/home/sam/tmp/py37/.tox/python/lib/python3.7/site-packages/redis/lock.py", line 222, in release
expected_token = self.local.token
AttributeError: '_thread._local' object has no attribute 'token'