Skip to content

Commit 59401cb

Browse files
committed
fix: don't fail if sentry doesn't return stats
1 parent 1d63b92 commit 59401cb

File tree

8 files changed

+56
-5
lines changed

8 files changed

+56
-5
lines changed

controller/sentry/detector.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from copy import copy
55
from statistics import mean, stdev
66

7+
from controller.sentry.exceptions import SentryNoOutcomeException
78
from controller.sentry.models import Project
89

910

@@ -79,13 +80,16 @@ def compute_sentry(self, stats: dict) -> tuple[OrderedDict, dict[str, list]]:
7980
Returns:
8081
OrderedDict: Annotated signal
8182
dict[str, list]: Full algorithm results
83+
84+
Raises:
85+
SentryNoOutcomeException: When there is no series with accepted outcome
8286
"""
8387
series = next(
8488
(group["series"]["sum(quantity)"] for group in stats["groups"] if group["by"]["outcome"] == "accepted"),
8589
None,
8690
)
8791
if series is None:
88-
raise ValueError("No series with accepted outcome")
92+
raise SentryNoOutcomeException("No series with accepted outcome")
8993

9094
signal, avg_filter, std_filter = self.compute(series)
9195

controller/sentry/exceptions.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Exceptions."""
2+
3+
4+
class SentryException(Exception):
5+
"""All sentry related Exception."""
6+
7+
8+
class SentryNoOutcomeException(Exception):
9+
"""Exception Raised when sentry doesn't return any stats."""

controller/sentry/tasks.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from controller.sentry.choices import EventType
1414
from controller.sentry.detector import SpikesDetector
15+
from controller.sentry.exceptions import SentryNoOutcomeException
1516
from controller.sentry.models import App, Event, Project
1617
from controller.sentry.webservices.sentry import PaginatedSentryClient
1718

@@ -133,7 +134,10 @@ def perform_detect(sentry_id) -> None:
133134

134135
stats = client.get_stats(project.sentry_id)
135136
detector = SpikesDetector.from_project(project)
136-
res, dump = detector.compute_sentry(stats)
137+
try:
138+
res, dump = detector.compute_sentry(stats)
139+
except SentryNoOutcomeException:
140+
return
137141

138142
project.detection_result = dump
139143
project.save()

controller/sentry/tests/test_detector.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import pytest
44

55
from controller.sentry.detector import SpikesDetector
6+
from controller.sentry.exceptions import SentryNoOutcomeException
67
from controller.sentry.models import Project
78

89

@@ -41,5 +42,5 @@ def test_spike_detector_empty():
4142
assert detector.threshold == project.detection_param["threshold"]
4243
assert detector.influence == project.detection_param["influence"]
4344

44-
with pytest.raises(ValueError):
45+
with pytest.raises(SentryNoOutcomeException):
4546
detector.compute_sentry({"groups": []})

controller/sentry/tests/test_tasks.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from django.utils import timezone
99

1010
from controller.sentry.choices import EventType
11+
from controller.sentry.exceptions import SentryNoOutcomeException
1112
from controller.sentry.models import App, Event, Project
1213
from controller.sentry.tasks import (
1314
close_window,
@@ -185,3 +186,27 @@ def test_perform_detect(spike_detector_mock: MagicMock, client_mock: MagicMock):
185186
project.refresh_from_db()
186187
assert project.events.exclude(reference=event.reference).count() == 2
187188
assert project.detection_result == dump
189+
190+
191+
@patch("controller.sentry.tasks.PaginatedSentryClient")
192+
@patch("controller.sentry.tasks.SpikesDetector")
193+
@pytest.mark.django_db
194+
def test_perform_detect_no_data(spike_detector_mock: MagicMock, client_mock: MagicMock):
195+
sentry_id = "123"
196+
project = Project(sentry_id=sentry_id)
197+
project.save()
198+
199+
detector: MagicMock = spike_detector_mock.from_project.return_value
200+
dump = {"test": "a"}
201+
detector.compute_sentry.side_effect = SentryNoOutcomeException
202+
203+
perform_detect(sentry_id)
204+
205+
client_mock.assert_called_once_with()
206+
client_mock.return_value.get_stats.assert_called_once_with(sentry_id)
207+
208+
spike_detector_mock.from_project.assert_called_once_with(project)
209+
210+
project.refresh_from_db()
211+
assert project.events.count() == 0
212+
assert project.detection_result is None

docs/how_does_it_work.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ If you still reach your sentry quotas, you can enable the panic mode. This mode
4646

4747

4848
Smart Features
49-
-------------
49+
--------------
5050
Every hour the controller fetch every project stats on Sentry. Using this stats we can detect misbehaving apps.
5151
For each misbehaving we create one :class:`event <controller.sentry.models.Event>` when the surge in transaction starts and one when it's end.
5252

docs/references/sentry.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ Submodules
2222
sentry/auth
2323
sentry/choices
2424
sentry/detector
25+
sentry/exceptions
2526
sentry/forms
2627
sentry/inlines
2728
sentry/mixins
2829
sentry/models
2930
sentry/serializers
3031
sentry/tasks
3132
sentry/utils
32-
sentry/views
33+
sentry/views

docs/references/sentry/exceptions.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Exceptions
2+
==========
3+
4+
.. automodule:: controller.sentry.exceptions
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

0 commit comments

Comments
 (0)