Skip to content

fix(sentry): reset the repetition throttle on quiet, not on the clock - #3428

Draft
vpetersson-bot wants to merge 2 commits into
masterfrom
agent/anthias-claude/e562cf5b2a91
Draft

vpetersson-bot wants to merge 2 commits into
masterfrom
agent/anthias-claude/e562cf5b2a91

Conversation

@vpetersson-bot

Copy link
Copy Markdown
Contributor

Issues Fixed

The per-issue repetition throttle added in #3400 thins a looping
device down to the powers of two, but it counted over a fixed
one-hour window. A loop that never pauses therefore restarted the
1, 2, 4, 8, ... sequence on every hour boundary and collected a
fresh budget with it — O(log n) per hour, which for a loop that
does not end is just a slower O(n).

That is the shape of the traffic the throttle exists to stop. The
board behind ANTHIAS-3H produced 1,761 copies of one error over 33
unbroken hours, about 53 an hour:

events for that run
no throttle 1,761
fixed one-hour window 198
this change 11

Description

  • _throttled now resets a key's count only after the issue has
    been quiet for a whole window, so the count spans the run of
    activity rather than the wall clock. The stored timestamp becomes
    "last seen" instead of "window started at".
  • _evict_throttle_keys drops keys by least-recently-seen, which
    falls out of the same change and is the better eviction order.
  • The trade is recorded in the comment: a long-running issue reports
    more sparsely the longer it runs, so its lastSeen lags. An issue
    carrying a throttle.occurrence tag of 262,144 still plainly
    reads as "constantly happening", and the quota it would otherwise
    spend is what silences every other issue in the project.

No behaviour change for the common case — a one-off error, or an
issue that recurs with gaps longer than the window, is unaffected.

tests/test_sentry.py gains a test that drives the throttle through
that real 53/hour-for-33-hours profile against a simulated clock and
asserts 11 kept events; it fails at 198 without the fix.

Checklist

  • I have performed a self-review of my own code.
  • New and existing unit tests pass locally and on CI with my changes.
  • I have done an end-to-end test for Raspberry Pi devices.
  • I have tested my changes for x86 devices.
  • I added a documentation for the changes I have made (when necessary).

Not hardware-tested: this is a pure in-process filter in
settings.py with no device-specific behaviour, covered by unit
tests. Full host suite run locally — tests/test_sentry.py 51/51,
and the failure set across the rest of the suite is byte-identical
with and without this change.

🤖 Generated with Claude Code

The per-issue throttle counted occurrences over a fixed one-hour
window, so a device whose loop never pauses restarted the 1, 2, 4,
8, ... sequence every hour and got a fresh budget with it.

- Key the reset on the issue going quiet for a window instead, so
  the count spans the whole run of activity.
- The board behind ANTHIAS-3H emitted ~53/hour for 33 unbroken
  hours: 198 events under the fixed window, 11 under this change.
- Evict throttle keys by least-recently-seen rather than by the
  oldest window start.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
@vpetersson-bot vpetersson-bot self-assigned this Oct 28, 2026
mypy rejects `settings.time` because the settings module does not
re-export `time`. Patching by import path targets the same object
without reaching through the module attribute.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant