* Add Check.last_start_rid field
* Fill Check.last_start_rid on every start event
* Clear Check.last_start on every "fail" event
* Clear Check.last_start on success event if either case is true:
- the event's rid matches Check.last_start_rid
- the event does not specify rid
In human terms, the alerting logic will be: we track the
execution time of the most recent "start" event only. It would
take a major redesign to track the execution time of all
concurrent "start" events and send alerts when *any* of them
overshoots the time budget. So, whenever we see a "start" event,
the timer resets.
Example:
* 00:00 client sends start signal with rid=A, timer starts
* 00:10 client sends start signal with rid=B, timer resets
* 00:20 client sends success signal with rid=A, timer
does not reset because rid A does not match the rid seen in
the most recent start signal (it was B)
* 00:30 the grace time runs out, the check's status shows
as started + failed
At this point the check can be reset to a healthy state in 3
different ways:
* send a success signal with rid=B
* send a failure signal with any rid value or without it
* send a success signal without a rid value
If every fetched ping is a success event, and has an unique
run ID, then we cannot determine the duration just from the
fetched data, and must fall back to Ping.duration(). This
would generate a SQL query per displayed ping.
The solution is to count how many times we would need to use
the fallback, and if it goes above some threshold (currently,
10 times), then disable duration display altogether.
The bug: _get_events sometimes does not have enough data to
calculate all durations correctly (some needed "start" events
may be outside the fetched data). The fix is to fall back to
Ping.duration() in these cases.
The code in hc.front.views.ping_details calculates durations
and sets them on the Ping.duration field, overriding the cached
property. But, it only does this for pings where the duration can
be calculated. If there's a streak of "success" pings with no
"start" pings between, the loop will not set the Ping.duration
field for most of them. So, when rendering the template, the
property code will run and cause an additional SQL query for each
ping. The fix is, in hc.front.views.ping_details, to set the
Ping.duration field for each and every ping.
* Added duration to ping details. This is useful on a device with a small screen, since the duration cannot be seen in the main view so now one can see it in the ping's details.
* Changed terms across the board from "delta" to "duration"
* timedelta is now consistently imported as "td" across the entire project (even in Django generated migration files)