1
0
Fork 0

Fix 500 error of stats page when cache isn't ready

Signed-off-by: Alfredos-Panagiotis Damkalis <fredy@fredy.gr>
spacecruft
Alfredos-Panagiotis Damkalis 2022-05-19 14:00:37 +03:00
parent 13e045164e
commit 6d5f0d1ba8
4 changed files with 54 additions and 13 deletions

View File

@ -10,6 +10,7 @@ from celery import shared_task
from django.conf import settings from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core.cache import cache
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.files import File from django.core.files import File
from django.core.mail import send_mail from django.core.mail import send_mail
@ -30,6 +31,12 @@ LOGGER = logging.getLogger('db')
CONTEXT = zmq.Context() CONTEXT = zmq.Context()
def delay_task_with_lock(task, lock_id, lock_expiration, *args):
"""Ensure unique run of a task by aquiring lock"""
if cache.add('{0}-{1}'.format(task.name, lock_id), '', lock_expiration):
task.delay(*args)
@shared_task @shared_task
def check_celery(): def check_celery():
"""Dummy celery task to check that everything runs smoothly.""" """Dummy celery task to check that everything runs smoothly."""

View File

@ -279,7 +279,7 @@ class PopulatedDBTest(TestCase):
# refresh statistics first # refresh statistics first
refresh = self.client.get('/statistics/') refresh = self.client.get('/statistics/')
response = self.client.get('/stats/') response = self.client.get('/stats/')
assertContains(response, 'Total Satellites') assertContains(response, 'calculation')
def test_robots(client): def test_robots(client):

View File

@ -11,7 +11,6 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.cache import cache from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.db import OperationalError
from django.db.models import Count, Max, Prefetch, Q from django.db.models import Count, Max, Prefetch, Q
from django.http import HttpResponse, HttpResponseServerError, JsonResponse from django.http import HttpResponse, HttpResponseServerError, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
@ -24,8 +23,9 @@ from db.base.forms import MergeSatellitesForm, SatelliteCreateForm, SatelliteUpd
from db.base.helpers import get_api_token from db.base.helpers import get_api_token
from db.base.models import DemodData, Satellite, SatelliteEntry, SatelliteIdentifier, \ from db.base.models import DemodData, Satellite, SatelliteEntry, SatelliteIdentifier, \
SatelliteSuggestion, Transmitter, TransmitterEntry, TransmitterSuggestion SatelliteSuggestion, Transmitter, TransmitterEntry, TransmitterSuggestion
from db.base.tasks import export_frames, notify_suggestion from db.base.tasks import background_cache_statistics, delay_task_with_lock, export_frames, \
from db.base.utils import cache_statistics, millify, read_influx notify_suggestion
from db.base.utils import millify, read_influx
LOGGER = logging.getLogger('db') LOGGER = logging.getLogger('db')
@ -334,18 +334,15 @@ def search(request):
def stats(request): def stats(request):
"""View to render stats page. """View to render stats page.
:returns: base/stats.html :returns: base/stats.html or base/calc-stats.html
""" """
cached_satellites = [] cached_satellites = []
ids = cache.get('satellites_ids') ids = cache.get('satellites_ids')
observers = cache.get('stats_observers') observers = cache.get('stats_observers')
if not ids or not observers: if not ids or not observers:
try: delay_task_with_lock(background_cache_statistics, 1, 3600)
cache_statistics() return render(request, 'base/calc-stats.html')
ids = cache.get('satellites_ids')
observers = cache.get('stats_observers')
except OperationalError:
pass
for sid in ids: for sid in ids:
stat = cache.get(sid) stat = cache.get(sid)
cached_satellites.append(stat) cached_satellites.append(stat)
@ -359,13 +356,12 @@ def stats(request):
def statistics(request): def statistics(request):
"""Triggers a refresh of cached statistics if the cache does not exist """Return transmitter cached statistics if the cache exist
:returns: JsonResponse of statistics :returns: JsonResponse of statistics
""" """
cached_stats = cache.get('stats_transmitters') cached_stats = cache.get('stats_transmitters')
if not cached_stats: if not cached_stats:
cache_statistics()
cached_stats = [] cached_stats = []
return JsonResponse(cached_stats, safe=False) return JsonResponse(cached_stats, safe=False)

View File

@ -0,0 +1,38 @@
{% extends "base.html" %}
{% load tags %}
{% load static %}
{% block title %} - Stats{% endblock %}
{% block top-menu-left %}
<span class="h4 mb-0 mr-3 text-truncate d-none d-md-block">Statistics</span>
{% endblock %}
{% block top %}
<span class="h4 mb-0">Statistics</span>
{% endblock %}
{% block content %}
<!-- SatNOGS DB Calculating Stats -->
<div class="container-fluid">
<div class="row justify-content-center">
<div class="col-md-9">
<div class="card card-info first-card">
<div class="card-header card-satnogs-header">
Statistics
</div>
<div class="card-body">
<p>
Statistics calculation is in progress and it may take several minutes to complete.
</p>
<p>
Please come back later!
</p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}