Files
bugsink/ingest/event_counter.py
2024-07-15 14:38:35 +02:00

54 lines
2.3 KiB
Python

from datetime import timezone, datetime
from django.db.models import Min
from bugsink.period_utils import add_periods_to_datetime, sub_periods_from_datetime
def _filter_for_periods(qs, period_name, nr_of_periods, now):
if period_name == "total":
return qs
return qs.filter(server_side_timestamp__gte=sub_periods_from_datetime(now, nr_of_periods, period_name))
def check_for_thresholds(qs, now, thresholds):
# thresholds :: [(period_name, nr_of_periods, gte_threshold, metadata), ...]
# we only allow UTC, and we generally use Django model fields, which are UTC, so this should be good:
assert now.tzinfo == timezone.utc
states_with_metadata = []
for (period_name, nr_of_periods, gte_threshold, metadata) in thresholds:
count = _filter_for_periods(qs, period_name, nr_of_periods, now).count()
state = count >= gte_threshold
if state:
if period_name == "total":
# when counting the 'total', there will never be a time when the condition becomes false. We
# just pick an arbitrarily large date; we'll deal with it by the end of the myria-annum.
# unlikely to actually end up in the DB (because it would imply the use of a quota for total).
below_threshold_from = datetime(9999, 12, 31, 23, 59, tzinfo=timezone.utc)
else:
# `below_threshold_from` is the first moment in time where the condition no longer applies.
# just get the min value of server-time over the qs:
below_threshold_from = add_periods_to_datetime(
_filter_for_periods(qs, period_name, nr_of_periods, now).aggregate(
agg=Min('server_side_timestamp'))['agg'],
nr_of_periods, period_name)
else:
below_threshold_from = None
states_with_metadata.append((state, below_threshold_from, metadata))
# we return tuples of (state, below_threshold_from, metadata) where metadata is something arbitrary that can be
# passed in (it allows us to tie back to "what caused this to be true/false?"
# TODO: I think that in practice the metadata is always implied by the thresholds, i.e. instead of
# passing-through we could just return the thresholds that were met.
return states_with_metadata