mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-11-02 03:40:31 +03:00
take the notice baseline at opt-in instead of the first send
The watermark reset ran at the first send attempt, so notices raised between the opt-in and that send, up to 45 minutes after a startup, were absorbed into the reset and never reported. The reporter now writes the new install ID and resets the watermarks as soon as it sees consent without a state file.
This commit is contained in:
@@ -127,6 +127,13 @@ class AnalyticsReporter(threading.Thread):
|
||||
|
||||
if opted_in:
|
||||
resolve_notice(PROMPT_KIND)
|
||||
|
||||
# a new install ID counts notices from the opt-in, so nothing
|
||||
# raised before consent is sent and nothing raised after is lost
|
||||
if load_state(self.state_path) is None and save_state(
|
||||
new_state(), self.state_path
|
||||
):
|
||||
self.notice_registry.mark_reported(self.notice_registry.stats())
|
||||
else:
|
||||
raise_notice(PROMPT_KIND)
|
||||
delete_state(self.state_path)
|
||||
@@ -151,8 +158,7 @@ class AnalyticsReporter(threading.Thread):
|
||||
if now < self.first_due:
|
||||
return
|
||||
|
||||
loaded = load_state(self.state_path)
|
||||
state = loaded or new_state()
|
||||
state = load_state(self.state_path) or new_state()
|
||||
|
||||
if not self._due(state.last_attempt_at, now):
|
||||
return
|
||||
@@ -179,7 +185,7 @@ class AnalyticsReporter(threading.Thread):
|
||||
self.interval = self._next_interval()
|
||||
|
||||
# the lock stays free during the request, so a save never waits on it
|
||||
self._send(state.install_id, now, fresh=loaded is None)
|
||||
self._send(state.install_id, now)
|
||||
|
||||
def _due(self, last_attempt_at: float, now: float) -> bool:
|
||||
# a last attempt stamped in the future came from a wrong clock
|
||||
@@ -187,12 +193,7 @@ class AnalyticsReporter(threading.Thread):
|
||||
now >= last_attempt_at + self.interval or last_attempt_at > now + INTERVAL_S
|
||||
)
|
||||
|
||||
def _send(self, install_id: str, now: float, fresh: bool) -> None:
|
||||
# a new install ID counts notices from the opt-in, so nothing raised
|
||||
# before consent is sent
|
||||
if fresh:
|
||||
self.notice_registry.mark_reported(self.notice_registry.stats())
|
||||
|
||||
def _send(self, install_id: str, now: float) -> None:
|
||||
notice_stats = self.notice_registry.stats()
|
||||
ctx = ReportContext(
|
||||
config=self.config_holder.config,
|
||||
|
||||
@@ -150,19 +150,26 @@ class TestAnalyticsReporter(unittest.TestCase):
|
||||
self.send.assert_called_once()
|
||||
self.registry.mark_reported.assert_not_called()
|
||||
|
||||
def test_a_new_install_id_skips_notices_from_before_the_opt_in(self):
|
||||
def test_a_new_install_id_counts_notices_from_the_opt_in(self):
|
||||
before = [{**SNAPSHOT[0], "occurrences": 2}]
|
||||
self.registry.stats.side_effect = [before, SNAPSHOT]
|
||||
self.registry.stats.return_value = before
|
||||
reporter = self.reporter()
|
||||
self.advance(FIRST_DELAY_S[0])
|
||||
|
||||
# consent is seen on the first wake, well before the first send
|
||||
reporter.tick()
|
||||
self.registry.mark_reported.assert_called_once_with(before)
|
||||
self.assertIsNotNone(load_state(self.path))
|
||||
self.send.assert_not_called()
|
||||
|
||||
# a notice raised during the startup delay goes out with the first report
|
||||
self.registry.stats.return_value = SNAPSHOT
|
||||
self.advance(FIRST_DELAY_S[0])
|
||||
reporter.tick()
|
||||
|
||||
# the reset runs before the report's snapshot, which the 204 then marks
|
||||
self.assertIs(self.build_report.call_args.args[0].notice_stats, SNAPSHOT)
|
||||
self.assertEqual(
|
||||
self.registry.mark_reported.call_args_list, [call(before), call(SNAPSHOT)]
|
||||
)
|
||||
self.assertIs(self.build_report.call_args.args[0].notice_stats, SNAPSHOT)
|
||||
|
||||
def test_an_opt_out_saved_only_to_the_file_stops_the_send(self):
|
||||
self.seed_state()
|
||||
|
||||
Reference in New Issue
Block a user