diff --git a/base_requirements.txt b/base_requirements.txt index 80f08f894..856439627 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -2,10 +2,6 @@ # https://github.com/django/django Django -# Django caching using Redis -# https://github.com/Suor/django-cacheops -django-cacheops - # Django middleware which permits cross-domain API requests # https://github.com/OttoYiu/django-cors-headers django-cors-headers @@ -34,6 +30,10 @@ django-pglocks # https://github.com/korfuri/django-prometheus django-prometheus +# Django chaching backend using Redis +# https://github.com/jazzband/django-redis +django-redis + # Django integration for RQ (Reqis queuing) # https://github.com/rq/django-rq django-rq diff --git a/docs/additional-features/caching.md b/docs/additional-features/caching.md deleted file mode 100644 index 18c9dca68..000000000 --- a/docs/additional-features/caching.md +++ /dev/null @@ -1,25 +0,0 @@ -# Caching - -NetBox supports database query caching using [django-cacheops](https://github.com/Suor/django-cacheops) and Redis. When a query is made, the results are cached in Redis for a short period of time, as defined by the [CACHE_TIMEOUT](../configuration/optional-settings.md#cache_timeout) parameter (15 minutes by default). Within that time, all recurrences of that specific query will return the pre-fetched results from the cache. - -If a change is made to any of the objects returned by the query within that time, or if the timeout expires, the results are automatically invalidated and the next request for those results will be sent to the database. - -## Invalidating Cached Data - -Although caching is performed automatically and rarely requires administrative intervention, NetBox provides the `invalidate` management command to force invalidation of cached results. This command can reference a specific object by its type and numeric ID: - -```no-highlight -$ python netbox/manage.py invalidate dcim.Device.34 -``` - -Alternatively, it can also delete all cached results for an object type: - -```no-highlight -$ python netbox/manage.py invalidate dcim.Device -``` - -Finally, calling it with the `all` argument will force invalidation of the entire cache database: - -```no-highlight -$ python netbox/manage.py invalidate all -``` diff --git a/docs/configuration/optional-settings.md b/docs/configuration/optional-settings.md index 31f7837de..8a9924bca 100644 --- a/docs/configuration/optional-settings.md +++ b/docs/configuration/optional-settings.md @@ -52,14 +52,6 @@ BASE_PATH = 'netbox/' --- -## CACHE_TIMEOUT - -Default: 900 - -The number of seconds that cache entries will be retained before expiring. - ---- - ## CHANGELOG_RETENTION Default: 90 diff --git a/docs/release-notes/version-3.0.md b/docs/release-notes/version-3.0.md index 20e438c7a..6f54448ca 100644 --- a/docs/release-notes/version-3.0.md +++ b/docs/release-notes/version-3.0.md @@ -68,6 +68,10 @@ CustomValidator can also be subclassed to enforce more complex logic by overridi * [#6338](https://github.com/netbox-community/netbox/issues/6338) - Decimal fields are no longer coerced to strings in REST API * [#6639](https://github.com/netbox-community/netbox/issues/6639) - Drop support for queryset caching (django-cacheops) +### Configuration Changes + +* The `CACHE_TIMEOUT` configuration parameter has been removed. + ### REST API Changes * Added the `/api/users/tokens/` endpoint diff --git a/netbox/netbox/configuration.example.py b/netbox/netbox/configuration.example.py index c6865a6ba..9491db27d 100644 --- a/netbox/netbox/configuration.example.py +++ b/netbox/netbox/configuration.example.py @@ -89,9 +89,6 @@ BANNER_LOGIN = '' # BASE_PATH = 'netbox/' BASE_PATH = '' -# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes) -CACHE_TIMEOUT = 900 - # Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) CHANGELOG_RETENTION = 90 diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 2b7ca50b8..22344938e 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -69,7 +69,6 @@ BANNER_TOP = getattr(configuration, 'BANNER_TOP', '') BASE_PATH = getattr(configuration, 'BASE_PATH', '') if BASE_PATH: BASE_PATH = BASE_PATH.strip('/') + '/' # Enforce trailing slash only -CACHE_TIMEOUT = getattr(configuration, 'CACHE_TIMEOUT', 900) CHANGELOG_RETENTION = getattr(configuration, 'CHANGELOG_RETENTION', 90) CORS_ORIGIN_ALLOW_ALL = getattr(configuration, 'CORS_ORIGIN_ALLOW_ALL', False) CORS_ORIGIN_REGEX_WHITELIST = getattr(configuration, 'CORS_ORIGIN_REGEX_WHITELIST', []) @@ -225,19 +224,30 @@ if 'caching' not in REDIS: raise ImproperlyConfigured( "REDIS section in configuration.py is missing caching subsection." ) -CACHING_REDIS = REDIS['caching'] -CACHING_REDIS_HOST = CACHING_REDIS.get('HOST', 'localhost') -CACHING_REDIS_PORT = CACHING_REDIS.get('PORT', 6379) -CACHING_REDIS_SENTINELS = CACHING_REDIS.get('SENTINELS', []) -CACHING_REDIS_USING_SENTINEL = all([ - isinstance(CACHING_REDIS_SENTINELS, (list, tuple)), - len(CACHING_REDIS_SENTINELS) > 0 -]) -CACHING_REDIS_SENTINEL_SERVICE = CACHING_REDIS.get('SENTINEL_SERVICE', 'default') -CACHING_REDIS_PASSWORD = CACHING_REDIS.get('PASSWORD', '') -CACHING_REDIS_DATABASE = CACHING_REDIS.get('DATABASE', 0) -CACHING_REDIS_SSL = CACHING_REDIS.get('SSL', False) -CACHING_REDIS_SKIP_TLS_VERIFY = CACHING_REDIS.get('INSECURE_SKIP_TLS_VERIFY', False) +CACHING_REDIS_HOST = REDIS['caching'].get('HOST', 'localhost') +CACHING_REDIS_PORT = REDIS['caching'].get('PORT', 6379) +CACHING_REDIS_DATABASE = REDIS['caching'].get('DATABASE', 0) +CACHING_REDIS_PASSWORD = REDIS['caching'].get('PASSWORD', '') +CACHING_REDIS_SENTINELS = REDIS['caching'].get('SENTINELS', []) +CACHING_REDIS_SENTINEL_SERVICE = REDIS['caching'].get('SENTINEL_SERVICE', 'default') +CACHING_REDIS_PROTO = 'rediss' if REDIS['caching'].get('SSL', False) else 'redis' +# Unused? +# CACHING_REDIS_SKIP_TLS_VERIFY = REDIS['caching'].get('INSECURE_SKIP_TLS_VERIFY', False) + +CACHES = { + 'default': { + 'BACKEND': 'django_redis.cache.RedisCache', + 'LOCATION': f'{CACHING_REDIS_PROTO}://{CACHING_REDIS_HOST}:{CACHING_REDIS_PORT}/{CACHING_REDIS_DATABASE}', + 'OPTIONS': { + 'CLIENT_CLASS': 'django_redis.client.DefaultClient', + 'PASSWORD': CACHING_REDIS_PASSWORD, + } + } +} +if CACHING_REDIS_SENTINELS: + CACHES['default']['LOCATION'] = f'{CACHING_REDIS_PROTO}://{CACHING_REDIS_SENTINEL_SERVICE}/{CACHING_REDIS_DATABASE}' + CACHES['default']['OPTIONS']['CLIENT_CLASS'] = 'django_redis.client.SentinelClient' + CACHES['default']['OPTIONS']['SENTINELS'] = CACHING_REDIS_SENTINELS # @@ -280,7 +290,6 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', - 'cacheops', 'corsheaders', 'debug_toolbar', 'graphiql_debug_toolbar', @@ -396,53 +405,6 @@ EXEMPT_EXCLUDE_MODELS = ( ('users', 'objectpermission'), ) -# -# Caching -# -if CACHING_REDIS_USING_SENTINEL: - CACHEOPS_SENTINEL = { - 'locations': CACHING_REDIS_SENTINELS, - 'service_name': CACHING_REDIS_SENTINEL_SERVICE, - 'db': CACHING_REDIS_DATABASE, - 'password': CACHING_REDIS_PASSWORD, - } -else: - CACHEOPS_REDIS = { - 'host': CACHING_REDIS_HOST, - 'port': CACHING_REDIS_PORT, - 'db': CACHING_REDIS_DATABASE, - 'password': CACHING_REDIS_PASSWORD, - 'ssl': CACHING_REDIS_SSL, - 'ssl_cert_reqs': None if CACHING_REDIS_SKIP_TLS_VERIFY else 'required', - } - -if not CACHE_TIMEOUT: - CACHEOPS_ENABLED = False -else: - CACHEOPS_ENABLED = True - - -CACHEOPS_DEFAULTS = { - 'timeout': CACHE_TIMEOUT -} -CACHEOPS = { - 'auth.user': {'ops': 'get', 'timeout': 60 * 15}, - 'auth.*': {'ops': ('fetch', 'get')}, - 'auth.permission': {'ops': 'all'}, - 'circuits.*': {'ops': 'all'}, - 'dcim.inventoryitem': None, # MPTT models are exempt due to raw SQL - 'dcim.region': None, # MPTT models are exempt due to raw SQL - 'dcim.location': None, # MPTT models are exempt due to raw SQL - 'dcim.*': {'ops': 'all'}, - 'ipam.*': {'ops': 'all'}, - 'extras.*': {'ops': 'all'}, - 'users.*': {'ops': 'all'}, - 'tenancy.tenantgroup': None, # MPTT models are exempt due to raw SQL - 'tenancy.*': {'ops': 'all'}, - 'virtualization.*': {'ops': 'all'}, -} -CACHEOPS_DEGRADE_ON_FAILURE = True - # # Django Prometheus diff --git a/requirements.txt b/requirements.txt index 1959e7c2e..2a1cecd66 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ Django==3.2.5 -django-cacheops==6.0 django-cors-headers==3.7.0 django-debug-toolbar==3.2.1 django-filter==2.4.0 @@ -7,6 +6,7 @@ django-graphiql-debug-toolbar==0.1.4 django-mptt==0.12.0 django-pglocks==1.0.4 django-prometheus==2.1.0 +django-redis==5.0.0 django-rq==2.4.1 django-tables2==2.4.0 django-taggit==1.5.1