1
0
Fork 0

use cached payload count in satellite view

merge-requests/319/head
Corey Shields 2019-01-06 12:34:10 -05:00
parent afd69f13ac
commit f8496b5899
5 changed files with 61 additions and 35 deletions

View File

@ -2,9 +2,7 @@ import csv
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.db.models import Count, Max
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django.core.mail import send_mail from django.core.mail import send_mail
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.template.loader import render_to_string from django.template.loader import render_to_string
@ -17,9 +15,9 @@ from sgp4.io import twoline2rv
from satellite_tle import fetch_tle_from_celestrak, fetch_tles from satellite_tle import fetch_tle_from_celestrak, fetch_tles
from db.base.models import Satellite, DemodData from db.base.models import Satellite, DemodData
from db.base.utils import calculate_statistics
from db.celery import app from db.celery import app
from db.base.utils import decode_data from db.base.utils import decode_data
from db.base.utils import cache_statistics
logger = logging.getLogger('db') logger = logging.getLogger('db')
@ -153,23 +151,9 @@ def export_frames(norad, email, uid, period=None):
@app.task @app.task
def cache_statistics(): def background_cache_statistics():
statistics = calculate_statistics() """Task to periodically cache statistics"""
cache.set('stats_transmitters', statistics, 60 * 60 * 2) cache_statistics()
satellites = Satellite.objects \
.values('name', 'norad_cat_id') \
.annotate(count=Count('telemetry_data'),
latest_payload=Max('telemetry_data__timestamp')) \
.order_by('-count')
cache.set('stats_satellites', satellites, 60 * 60 * 2)
observers = DemodData.objects \
.values('observer') \
.annotate(count=Count('observer'),
latest_payload=Max('timestamp')) \
.order_by('-count')
cache.set('stats_observers', observers, 60 * 60 * 2)
# resets all decoded data and changes the is_decoded flag back to False # resets all decoded data and changes the is_decoded flag back to False

View File

@ -3,10 +3,12 @@ import binascii
from datetime import datetime, timedelta from datetime import datetime, timedelta
from db.base.models import Satellite, Transmitter, Mode, DemodData, Telemetry from db.base.models import Satellite, Transmitter, Mode, DemodData, Telemetry
from django.db.models import Count, Max
from django.conf import settings from django.conf import settings
from django.utils.timezone import make_aware from django.utils.timezone import make_aware
from influxdb import InfluxDBClient from influxdb import InfluxDBClient
from satnogsdecoders import decoder from satnogsdecoders import decoder
from django.core.cache import cache
logger = logging.getLogger('db') logger = logging.getLogger('db')
@ -21,11 +23,14 @@ def calculate_statistics():
total_transmitters = transmitters.count() total_transmitters = transmitters.count()
total_data = DemodData.objects.all().count() total_data = DemodData.objects.all().count()
alive_transmitters = transmitters.filter(alive=True).count() alive_transmitters = transmitters.filter(alive=True).count()
try: if alive_transmitters > 0 and total_transmitters > 0:
alive_transmitters_percentage = '{0}%'.format(round((float(alive_transmitters) / try:
float(total_transmitters)) * 100, 2)) alive_transmitters_percentage = '{0}%'.format(round((float(alive_transmitters)
except ZeroDivisionError as error: / float(total_transmitters)) * 100, 2))
logger.error(error, exc_info=True) except ZeroDivisionError as error:
logger.error(error, exc_info=True)
alive_transmitters_percentage = '0%'
else:
alive_transmitters_percentage = '0%' alive_transmitters_percentage = '0%'
mode_label = [] mode_label = []
@ -35,6 +40,12 @@ def calculate_statistics():
mode_label.append(mode.name) mode_label.append(mode.name)
mode_data.append(tr) mode_data.append(tr)
# needed to pass testing in a fresh environment with no modes in db
if len(mode_label) == 0:
mode_label = ['FM']
if len(mode_data) == 0:
mode_data = ['FM']
band_label = [] band_label = []
band_data = [] band_data = []
@ -242,3 +253,23 @@ def decode_data(norad, period=None):
break break
except IOError: except IOError:
continue continue
# Caches stats about satellites and data
def cache_statistics():
statistics = calculate_statistics()
cache.set('stats_transmitters', statistics, 60 * 60 * 2)
satellites = Satellite.objects \
.values('name', 'norad_cat_id') \
.annotate(count=Count('telemetry_data'),
latest_payload=Max('telemetry_data__timestamp')) \
.order_by('-count')
cache.set('stats_satellites', satellites, 60 * 60 * 2)
observers = DemodData.objects \
.values('observer') \
.annotate(count=Count('observer'),
latest_payload=Max('timestamp')) \
.order_by('-count')
cache.set('stats_observers', observers, 60 * 60 * 2)

View File

@ -1,6 +1,6 @@
import logging import logging
from django.db.models import Count, Max from django.db.models import Max
from django.conf import settings from django.conf import settings
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -16,7 +16,8 @@ from django.views.decorators.http import require_POST
from db.base.models import Mode, Transmitter, Satellite, Suggestion, DemodData, TRANSMITTER_TYPE from db.base.models import Mode, Transmitter, Satellite, Suggestion, DemodData, TRANSMITTER_TYPE
from db.base.forms import SuggestionForm from db.base.forms import SuggestionForm
from db.base.helpers import get_apikey from db.base.helpers import get_apikey
from db.base.tasks import export_frames, cache_statistics from db.base.tasks import export_frames
from db.base.utils import cache_statistics
from _mysql_exceptions import OperationalError from _mysql_exceptions import OperationalError
@ -57,12 +58,21 @@ def robots(request):
def satellite(request, norad): def satellite(request, norad):
"""View to render satellite page.""" """View to render satellite page."""
satellite_query = Satellite.objects \ satellite_query = Satellite.objects \
.annotate(latest_payload_time=Max('telemetry_data__timestamp'), .annotate(latest_payload_time=Max('telemetry_data__timestamp'))
payload_frames_count=Count('telemetry_data'))
satellite = get_object_or_404(satellite_query, norad_cat_id=norad) satellite = get_object_or_404(satellite_query, norad_cat_id=norad)
suggestions = Suggestion.objects.filter(satellite=satellite) suggestions = Suggestion.objects.filter(satellite=satellite)
modes = Mode.objects.all() modes = Mode.objects.all()
types = TRANSMITTER_TYPE types = TRANSMITTER_TYPE
sats_cache = cache.get('stats_satellites')
if not sats_cache:
try:
cache_statistics()
except OperationalError:
pass
try:
sat_cache = sats_cache.filter(norad_cat_id=norad)
except AttributeError:
sat_cache = [{'count': 'err'}]
try: try:
latest_frame = DemodData.objects.get(satellite=satellite, latest_frame = DemodData.objects.get(satellite=satellite,
@ -75,6 +85,7 @@ def satellite(request, norad):
'modes': modes, 'modes': modes,
'types': types, 'types': types,
'latest_frame': latest_frame, 'latest_frame': latest_frame,
'sat_cache': sat_cache[0],
'mapbox_token': settings.MAPBOX_TOKEN}) 'mapbox_token': settings.MAPBOX_TOKEN})
@ -154,7 +165,7 @@ def stats(request):
observers = cache.get('stats_observers') observers = cache.get('stats_observers')
if not satellites or not observers: if not satellites or not observers:
try: try:
cache_statistics.delay() cache_statistics()
except OperationalError: except OperationalError:
pass pass
return render(request, 'base/stats.html', {'satellites': satellites, return render(request, 'base/stats.html', {'satellites': satellites,
@ -164,7 +175,7 @@ def stats(request):
def statistics(request): def statistics(request):
statistics = cache.get('stats_transmitters') statistics = cache.get('stats_transmitters')
if not statistics: if not statistics:
cache_statistics.delay() cache_statistics()
statistics = [] statistics = []
return JsonResponse(statistics, safe=False) return JsonResponse(statistics, safe=False)

View File

@ -20,13 +20,13 @@ app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.on_after_finalize.connect @app.on_after_finalize.connect
def setup_periodic_tasks(sender, **kwargs): def setup_periodic_tasks(sender, **kwargs):
from db.base.tasks import update_all_tle, cache_statistics, decode_recent_data from db.base.tasks import update_all_tle, background_cache_statistics, decode_recent_data
sender.add_periodic_task(RUN_DAILY, update_all_tle.s(), sender.add_periodic_task(RUN_DAILY, update_all_tle.s(),
name='update-all-tle') name='update-all-tle')
sender.add_periodic_task(RUN_HOURLY, cache_statistics.s(), sender.add_periodic_task(RUN_HOURLY, background_cache_statistics.s(),
name='cache-statistics') name='background-cache-statistics')
sender.add_periodic_task(RUN_EVERY_15, decode_recent_data.s(), sender.add_periodic_task(RUN_EVERY_15, decode_recent_data.s(),
name='decode-recent-data') name='decode-recent-data')

View File

@ -462,7 +462,7 @@
</div> </div>
{% endif %} {% endif %}
<div class="panel-footer"> <div class="panel-footer">
<span class="badge">Frames: {{ satellite.payload_frames_count }}</span> <span class="badge">Frames: {{ sat_cache.count }}</span>
Latest frame submitted on {{ latest_frame.timestamp|date:'Y-m-d H:i:s' }} by Latest frame submitted on {{ latest_frame.timestamp|date:'Y-m-d H:i:s' }} by
{{ latest_frame.observer }} {{ latest_frame.observer }}
</div> </div>