mirror of
https://github.com/healthchecks/healthchecks.git
synced 2025-04-07 22:25:35 +00:00
Simplify DowntimeSummary
This commit is contained in:
parent
f7af738c76
commit
58d7c8cc55
4 changed files with 30 additions and 32 deletions
hc
|
@ -241,11 +241,14 @@ class Profile(models.Model):
|
|||
|
||||
for check in checks:
|
||||
downtimes = check.downtimes_by_boundary(boundaries, self.tz)
|
||||
# downtimes_by_boundary returns records in descending order.
|
||||
# Switch to ascending order:
|
||||
# downtimes_by_boundary returns records in descending order,
|
||||
# but the template will need them in ascending order:
|
||||
downtimes.reverse()
|
||||
setattr(check, "past_downtimes", downtimes[:-1])
|
||||
|
||||
# boundaries are in descending order, but the template
|
||||
# will need them in ascending order:
|
||||
boundaries.reverse()
|
||||
ctx["checks"] = checks
|
||||
ctx["boundaries"] = boundaries[:-1]
|
||||
ctx["monthly_or_weekly"] = self.reports
|
||||
|
|
|
@ -149,25 +149,19 @@ class DowntimeRecord:
|
|||
|
||||
class DowntimeSummary(object):
|
||||
def __init__(self, boundaries: list[datetime], tz: str) -> None:
|
||||
self.boundaries = list(sorted(boundaries, reverse=True))
|
||||
self.durations = [td() for _ in boundaries]
|
||||
self.counts = [0 for _ in boundaries]
|
||||
self.tz = tz
|
||||
"""
|
||||
`boundaries` are timezone-aware datetimes of the first days of time intervals
|
||||
(months or weeks), and should be pre-sorted in descending order.
|
||||
"""
|
||||
self.records = [DowntimeRecord(b, tz, td(), 0) for b in boundaries]
|
||||
|
||||
def add(self, when: datetime, duration: td) -> None:
|
||||
for i in range(0, len(self.boundaries)):
|
||||
if when >= self.boundaries[i]:
|
||||
self.durations[i] += duration
|
||||
self.counts[i] += 1
|
||||
for record in self.records:
|
||||
if when >= record.boundary:
|
||||
record.duration += duration
|
||||
record.count += 1
|
||||
return
|
||||
|
||||
def as_records(self) -> list[DowntimeRecord]:
|
||||
result = []
|
||||
for b, d, c in zip(self.boundaries, self.durations, self.counts):
|
||||
result.append(DowntimeRecord(b, self.tz, d, c))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class Check(models.Model):
|
||||
name = models.CharField(max_length=100, blank=True)
|
||||
|
@ -514,8 +508,8 @@ class Check(models.Model):
|
|||
|
||||
Returns a list of DowntimeRecord instances in descending datetime order.
|
||||
|
||||
`boundaries` are the datetimes of the first days of time intervals
|
||||
(months or weeks) we're interested in, in ascending order.
|
||||
`boundaries` are timezone-aware datetimes of the first days of time intervals
|
||||
(months or weeks), and should be pre-sorted in descending order.
|
||||
|
||||
"""
|
||||
|
||||
|
@ -543,14 +537,13 @@ class Check(models.Model):
|
|||
|
||||
# Set count to None for intervals when the check didn't exist yet
|
||||
prev_boundary = None
|
||||
results = summary.as_records()
|
||||
for record in results:
|
||||
for record in summary.records:
|
||||
if prev_boundary and self.created > prev_boundary:
|
||||
record.count = None
|
||||
|
||||
prev_boundary = record.boundary
|
||||
|
||||
return results
|
||||
return summary.records
|
||||
|
||||
def downtimes(self, months: int, tz: str) -> list[DowntimeRecord]:
|
||||
boundaries = month_boundaries(months, tz)
|
||||
|
|
|
@ -75,13 +75,14 @@ def format_approx_duration(duration: timedelta) -> str:
|
|||
|
||||
|
||||
def month_boundaries(months: int, tzstr: str) -> list[datetime]:
|
||||
"""Return month start times in descending order starting from the current month."""
|
||||
tz = ZoneInfo(tzstr)
|
||||
result: list[datetime] = []
|
||||
|
||||
now_value = now().astimezone(tz)
|
||||
y, m = now_value.year, now_value.month
|
||||
for x in range(0, months):
|
||||
result.insert(0, datetime(y, m, 1, tzinfo=tz))
|
||||
result.append(datetime(y, m, 1, tzinfo=tz))
|
||||
|
||||
m -= 1
|
||||
if m == 0:
|
||||
|
@ -92,13 +93,14 @@ def month_boundaries(months: int, tzstr: str) -> list[datetime]:
|
|||
|
||||
|
||||
def week_boundaries(weeks: int, tzstr: str) -> list[datetime]:
|
||||
"""Return week start times in descending order starting from the current week."""
|
||||
tz = ZoneInfo(tzstr)
|
||||
result: list[datetime] = []
|
||||
|
||||
today = now().astimezone(tz).date()
|
||||
needle = today - timedelta(days=today.weekday())
|
||||
for x in range(0, weeks):
|
||||
result.insert(0, datetime(needle.year, needle.month, needle.day, tzinfo=tz))
|
||||
result.append(datetime(needle.year, needle.month, needle.day, tzinfo=tz))
|
||||
needle -= timedelta(days=7)
|
||||
|
||||
return result
|
||||
|
|
|
@ -42,30 +42,30 @@ class DateFormattingTestCase(TestCase):
|
|||
class MonthBoundaryTestCase(TestCase):
|
||||
def test_utc_works(self) -> None:
|
||||
result = month_boundaries(3, "UTC")
|
||||
self.assertEqual(result[0].isoformat(), "2019-11-01T00:00:00+00:00")
|
||||
self.assertEqual(result[0].isoformat(), "2020-01-01T00:00:00+00:00")
|
||||
self.assertEqual(result[1].isoformat(), "2019-12-01T00:00:00+00:00")
|
||||
self.assertEqual(result[2].isoformat(), "2020-01-01T00:00:00+00:00")
|
||||
self.assertEqual(result[2].isoformat(), "2019-11-01T00:00:00+00:00")
|
||||
|
||||
def test_non_utc_works(self) -> None:
|
||||
result = month_boundaries(3, "Europe/Riga")
|
||||
self.assertEqual(result[0].isoformat(), "2019-11-01T00:00:00+02:00")
|
||||
self.assertEqual(result[0].isoformat(), "2020-01-01T00:00:00+02:00")
|
||||
self.assertEqual(result[1].isoformat(), "2019-12-01T00:00:00+02:00")
|
||||
self.assertEqual(result[2].isoformat(), "2020-01-01T00:00:00+02:00")
|
||||
self.assertEqual(result[2].isoformat(), "2019-11-01T00:00:00+02:00")
|
||||
|
||||
|
||||
@patch("hc.lib.date.now", MOCK_NOW)
|
||||
class WeekBoundaryTestCase(TestCase):
|
||||
def test_utc_works(self) -> None:
|
||||
result = week_boundaries(3, "UTC")
|
||||
self.assertEqual(result[0].isoformat(), "2019-12-30T00:00:00+00:00")
|
||||
self.assertEqual(result[0].isoformat(), "2020-01-13T00:00:00+00:00")
|
||||
self.assertEqual(result[1].isoformat(), "2020-01-06T00:00:00+00:00")
|
||||
self.assertEqual(result[2].isoformat(), "2020-01-13T00:00:00+00:00")
|
||||
self.assertEqual(result[2].isoformat(), "2019-12-30T00:00:00+00:00")
|
||||
|
||||
def test_non_utc_works(self) -> None:
|
||||
result = week_boundaries(3, "Europe/Riga")
|
||||
self.assertEqual(result[0].isoformat(), "2019-12-30T00:00:00+02:00")
|
||||
self.assertEqual(result[0].isoformat(), "2020-01-13T00:00:00+02:00")
|
||||
self.assertEqual(result[1].isoformat(), "2020-01-06T00:00:00+02:00")
|
||||
self.assertEqual(result[2].isoformat(), "2020-01-13T00:00:00+02:00")
|
||||
self.assertEqual(result[2].isoformat(), "2019-12-30T00:00:00+02:00")
|
||||
|
||||
|
||||
class SecondsInMonthTestCase(TestCase):
|
||||
|
|
Loading…
Add table
Reference in a new issue