New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default Redis Locking (thread locals) Incompatible with Async Creators #171
Comments
would exposing the Redis lock "thread_local" parameter be sufficient ? |
Yeah, but it might be better to have dogpile 'handle' it so that people can't configure themselves into using async creators with thread local locking. iow: dogpile can use thread local locking for synchronous creations and then disable it when creating locks for asynchronous flows. Or perhaps always disable thread locals? Because the tokens used are per key, not for global locking. |
It's already news to me, since I dont pay attention to redis, that their lock uses a thread local. so they might change this later. i would be OK emitting a warning but assuming redis' use of this thread local is somehow required, I'd rather not guess our way around a changing set of third party behaviors.
is that why they are using a threadlocal ? this really seems like a bug on their end, that's crazy? of course, if the lock doesnt need this behavior we should just turn it off, sure. |
cc @jvanasco since I think you follow redis etc. any insight on this? |
Here's the Python client's docs on the purpose of the thread local implementation:
I think in this example, a single lock is being used to coordinate activity for multiple tokens (1 'thread global' lock for all cache key being recomputed in said thread). Whereas in dogpile's case with asynchronous creators, it's more like multiple locks are being used (1 per key) for 1 token. And at the end of that function's doc, we have:
I also don't follow redis actively so insight and corrections are more than welcome here. |
IMO that's a pretty broken API. the lock should generate a unique token for the acquire() operation, return it to the caller, then the caller makes use of that token when they call release(). this is basically what they are doing with thread local thing now, just that it's hardcoded to the current thread id. it should not be linked to the thread, it should be linked to the caller. |
see I'd want redis.py to support this case more explciitly. their note "these cases aren't common so it will just break" is not really good enough |
ill add a warning |
Sam Park has proposed a fix for this issue in the master branch: Add option for thread local Redis locks https://gerrit.sqlalchemy.org/c/sqlalchemy/dogpile.cache/+/1783 |
Change-Id: I955c56377b3bfe3871b2443b0433ea3db975bd91
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:
The text was updated successfully, but these errors were encountered: