agateblue / django-dynamic-preferences

Dynamic global and instance settings for your django project
https://django-dynamic-preferences.readthedocs.org/
BSD 3-Clause "New" or "Revised" License
350 stars 87 forks source link

The documentation regarding the use of global_preferences_registry.manager() is not clear #168

Open serbant opened 5 years ago

serbant commented 5 years ago

the documentation suggests that a pattern as below works

prefs = global_preferences_registry.manager()
my_preference = prefs.get('my_section__my_ name')

it does but it will not pick the current value of the preference. one needs to use something along the lines of

def get_preference(key=None):
    """
    get the preference
    """
    preferences = global_preferences_registry.manager().load_from_db()
    try:
        return preferences.get(key)
    except Exception as error:
        raise error

I suggest that the documentation is updated to reflect this

agateblue commented 5 years ago

@serbant prefs.get('my_section__my_name') should use the value from the cache, and the cache is invalidated on any database change (otherwise it's a bug).

Can you please share a complete code example to reproduce your issue?

serbant commented 5 years ago

if you take my first code sample and print the my_preference, then, without killing the shell, you change and save the value for my_preference, and then you come back to the shell and you print my_preference, you will note that print returns the old value, not, as expected, the new value. something like this

# other code

PREFS=global_preferences_registry.manager()

@shared_task
def celery_task(send_no_news=None):
    """
    had this happen in a celery task
    """
    if send_no_news is None:
        send_no_news = PREFS.get('citrusborgcommon__send_no_news')
    return send_no_news

with the task executing on a periodic basis, changes to the preference value are not reflected in the task return.

if i replace PREFS.get() with the get_preference() function shown above, changes are reflected

agateblue commented 5 years ago

I'd like to know how your cache if configured. If you're using an in-process cache backend and not a cross-process one like redis, db or memcached, it's indeed possible that cache is not being invalidated properly in your celery process when you update a preference value in your web process.

You can either configure a cross-process cache backend, or tell django-dynamic-preferences not to cache anything, in your settings:

DYNAMIC_PREFERENCES = {
    'ENABLE_CACHE': False
}

Keep in mind that this will to one DB request every time you want to access a preference value, so this can have performance impact depending on your workload and the way your app is designed.

serbant commented 5 years ago

i'm using the default django cache configuration which if i understand correctly is a per-process cache, see ( https://docs.djangoproject.com/en/2.1/topics/cache/#local-memory-caching)

On Tue, Jan 8, 2019 at 10:37 AM Eliot Berriot notifications@github.com wrote:

I'd like to know how your cache if configured. If you're using an in-process cache backend and not a cross-process one like redis, db or memcached, it's indeed possible that cache is not being invalidated properly in your celery process when you update a preference value in your web process.

You can either configure a cross-process cache backend, or tell django-dynamic-preferences not to cache anything, in your settings https://django-dynamic-preferences.readthedocs.io/en/latest/installation.html#settings :

DYNAMIC_PREFERENCES = { 'ENABLE_CACHE': True }

Keep in mind that this will to one DB request every time you want to access a preference value, so this can have performance impact depending on your workload and the way your app is designed.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/EliotBerriot/django-dynamic-preferences/issues/168#issuecomment-452405481, or mute the thread https://github.com/notifications/unsubscribe-auth/ABswzNr8MJozLGciwTidSohPk-2ZRfX-ks5vBOVzgaJpZM4Z0aJ9 .

lorenzomorandini commented 5 years ago

I agree that there is indeed a bug or something regarding the cache. I have a standard django cache config and I keep getting different results when getting a preference, even if I instantiate the manager inside the function (so not at import time). I'm trying with ENABLE_CACHE=False right now, hoping it will fix this

felixrindt commented 1 year ago

Stumbling upon this again. The documentation reads: image

but when I look at

https://github.com/agateblue/django-dynamic-preferences/blob/32f1bf444888b0a0dd95f8601d07000780c2a7e5/dynamic_preferences/managers.py#L36-L40

and

https://github.com/agateblue/django-dynamic-preferences/blob/32f1bf444888b0a0dd95f8601d07000780c2a7e5/dynamic_preferences/managers.py#L164-L180

I am not seeing where the cache is being invalidated (step 3 from the docs)?! Is there some magic I am missing? Is it using some receiver to the signal? I am not seeing this problem when using redis (only with the default LocMemCache), but I don't understand why :sweat_smile: