Skip to content

Commit

Permalink
Merge pull request #2563 from stveit/ranked-stats-caching-crash
Browse files Browse the repository at this point in the history
Add errorhandling for missing cache in ranked statistics
  • Loading branch information
stveit authored Mar 22, 2023
2 parents c528567 + 199cb16 commit 2a68344
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 10 deletions.
31 changes: 27 additions & 4 deletions python/nav/web/sortedstats/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,27 @@
from django.shortcuts import render
from django.core.cache import caches
from django.conf import settings
from django.core.cache.backends.base import InvalidCacheBackendError

from .forms import ViewForm
from . import CLASSMAP, TIMEFRAMES
from nav.metrics.errors import GraphiteUnreachableError

GRAPHITE_TIME_FORMAT = "%H:%M_%Y%m%d"
_logger = logging.getLogger(__name__)
cache = caches['sortedstats']


def get_cache():
return caches['sortedstats']


def cache_is_misconfigured():
try:
get_cache()
except InvalidCacheBackendError:
return True
else:
return False


def index(request):
Expand Down Expand Up @@ -64,6 +77,7 @@ def index(request):
'graphite_unreachable': graphite_unreachable,
'from_cache': from_cache,
'duration': duration,
'cache_misconfigured': cache_is_misconfigured(),
}

return render(request, 'sortedstats/sortedstats.html', context)
Expand All @@ -78,8 +92,13 @@ def process_form(form):
rows = form.cleaned_data['rows']
cache_key = get_cache_key(view, timeframe, rows)
if form.cleaned_data['use_cache']:
result = cache.get(cache_key)
if result and not result.data:
try:
cache = get_cache()
result = cache.get(cache_key)
if result and not result.data:
result = None
except InvalidCacheBackendError as e:
_logger.error("Error accessing cache for ranked statistics: %s", e)
result = None
if not result:
result = collect_result(view, timeframe, rows)
Expand All @@ -106,7 +125,11 @@ def collect_result(view, timeframe, rows):
cache_key = get_cache_key(view, timeframe, rows)
result = get_result(view, start, end, rows)
result.collect()
cache.set(cache_key, result, timeout=timeout)
try:
cache = get_cache()
cache.set(cache_key, result, timeout=timeout)
except InvalidCacheBackendError as e:
_logger.error("Error accessing cache for ranked statistics: %s", e)
return result


Expand Down
5 changes: 5 additions & 0 deletions python/nav/web/templates/sortedstats/sortedstats.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
{% include 'nav_header.html' %}
{% endwith %}

{% if cache_misconfigured %}
<div class="alert-box error">
The cache for Ranked Statistics is not configured correctly.
</div>
{% endif %}

{% crispy form %}

Expand Down
12 changes: 6 additions & 6 deletions tests/unittests/web/sortedstats/sortedstats_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ def test_cache_key_is_correct(self):
cache_key = views.get_cache_key(view, timeframe, rows)
self.assertEqual(cache_key, expected_cache_key)

@patch('nav.web.sortedstats.views.cache')
@patch('nav.web.sortedstats.views.get_cache')
def test_process_form_returns_cache_value_if_cache_exists(self, cache_mock):
data = "cached"
cache_mock.get.return_value.data = data
cache_mock.return_value.get.return_value.data = data
fake_form = MagicMock()
fake_form.cleaned_data = {
'view': 'uptime',
Expand All @@ -42,12 +42,12 @@ def test_process_form_returns_cache_value_if_cache_exists(self, cache_mock):
self.assertEqual(result.data, data)

@patch('nav.web.sortedstats.views.collect_result')
@patch('nav.web.sortedstats.views.cache')
@patch('nav.web.sortedstats.views.get_cache')
def test_cache_not_used_if_empty_and_use_cache_is_on(
self, cache_mock, collect_mock
):
data = "new"
cache_mock.get.return_value.data = ""
cache_mock.return_value.get.return_value.data = ""
collect_mock.return_value.data = data
fake_form = MagicMock()
fake_form.cleaned_data = {
Expand All @@ -61,12 +61,12 @@ def test_cache_not_used_if_empty_and_use_cache_is_on(
self.assertEqual(result.data, data)

@patch('nav.web.sortedstats.views.collect_result')
@patch('nav.web.sortedstats.views.cache')
@patch('nav.web.sortedstats.views.get_cache')
def test_cache_not_used_if_empty_and_use_cache_is_off(
self, cache_mock, collect_mock
):
data = "new"
cache_mock.get.return_value.data = ""
cache_mock.return_value.get.return_value.data = ""
collect_mock.return_value.data = data
fake_form = MagicMock()
fake_form.cleaned_data = {
Expand Down

0 comments on commit 2a68344

Please sign in to comment.