Skip to content

Commit ac0c828

Browse files
committed
Store issue freqs for [release+env]
This adjusts the tsdb storage for release frequencies to use the new GroupRelease which is bound to an environment. /cc @getsentry/infrastructure
1 parent d0b4e65 commit ac0c828

File tree

4 files changed

+132
-37
lines changed

4 files changed

+132
-37
lines changed

src/sentry/event_manager.py

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -559,16 +559,41 @@ def save(self, project, raw=False):
559559

560560
if release:
561561
# TODO(dcramer): would be a bit more ideal to buffer this
562-
GroupRelease.objects.create_or_update(
563-
project_id=project.id,
564-
release_id=release.id,
565-
group_id=group.id,
566-
environment=environment or '',
567-
values={
568-
'last_seen': date,
569-
}
562+
grouprelease = GroupRelease.get_or_create(
563+
group=group,
564+
release=release,
565+
environment=environment,
566+
datetime=date,
567+
)
568+
569+
tsdb.incr_multi([
570+
(tsdb.models.group, group.id),
571+
(tsdb.models.project, project.id),
572+
], timestamp=event.datetime)
573+
574+
frequencies = [
575+
(tsdb.models.frequent_projects_by_organization, {
576+
project.organization_id: {
577+
project.id: 1,
578+
},
579+
}),
580+
(tsdb.models.frequent_issues_by_project, {
581+
project.id: {
582+
group.id: 1,
583+
},
584+
})
585+
]
586+
if release:
587+
frequencies.append(
588+
(tsdb.models.frequent_releases_by_groups, {
589+
group.id: {
590+
grouprelease.id: 1,
591+
},
592+
})
570593
)
571594

595+
tsdb.record_frequency_multi(frequencies, timestamp=event.datetime)
596+
572597
UserReport.objects.filter(
573598
project=project, event_id=event_id,
574599
).update(group=group)
@@ -761,34 +786,6 @@ def _save_aggregate(self, event, hashes, release, **kwargs):
761786
else:
762787
is_sample = can_sample
763788

764-
tsdb.incr_multi([
765-
(tsdb.models.group, group.id),
766-
(tsdb.models.project, project.id),
767-
], timestamp=event.datetime)
768-
769-
frequencies = [
770-
(tsdb.models.frequent_projects_by_organization, {
771-
project.organization_id: {
772-
project.id: 1,
773-
},
774-
}),
775-
(tsdb.models.frequent_issues_by_project, {
776-
project.id: {
777-
group.id: 1,
778-
},
779-
})
780-
]
781-
if release:
782-
frequencies.append(
783-
(tsdb.models.frequent_releases_by_groups, {
784-
group.id: {
785-
release.id: 1,
786-
},
787-
})
788-
)
789-
790-
tsdb.record_frequency_multi(frequencies, timestamp=event.datetime)
791-
792789
return group, is_new, is_regression, is_sample
793790

794791
def _handle_regression(self, group, event, release):

src/sentry/models/grouprelease.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from django.db import models
44
from django.utils import timezone
5+
from hashlib import md5
56

7+
from sentry.utils.cache import cache
68
from sentry.db.models import (
79
BoundedPositiveIntegerField, Model, sane_repr
810
)
@@ -24,3 +26,39 @@ class Meta:
2426
unique_together = (('group_id', 'release_id', 'environment'),)
2527

2628
__repr__ = sane_repr('group_id', 'release_id')
29+
30+
@classmethod
31+
def get_cache_key(cls, group_id, release_id, environment):
32+
return 'grouprelease:1:{}:{}'.format(
33+
group_id,
34+
md5('{}:{}'.format(release_id, environment)).hexdigest(),
35+
)
36+
37+
@classmethod
38+
def get_or_create(cls, group, release, environment, datetime, **kwargs):
39+
if not environment:
40+
environment = ''
41+
cache_key = cls.get_cache_key(group.id, release.id, environment)
42+
43+
instance = cache.get(cache_key)
44+
if instance is None:
45+
# TODO(dcramer): if the cache result is -1 we could attempt a
46+
# default create here instead of default get
47+
instance, created = cls.objects.get_or_create(
48+
release_id=release.id,
49+
group_id=group.id,
50+
environment=environment,
51+
defaults={
52+
'project_id': group.project_id,
53+
'first_seen': datetime,
54+
'last_seen': datetime,
55+
},
56+
)
57+
cache.set(cache_key, instance, 3600)
58+
else:
59+
created = False
60+
61+
# TODO(dcramer): this would be good to buffer
62+
if not created:
63+
instance.update(last_seen=datetime)
64+
return instance

src/sentry/tsdb/base.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ class TSDBModel(Enum):
6262
# number of issues seen for a project, by project
6363
frequent_issues_by_project = 404
6464
# number of events seen for a release, by issue
65-
frequent_releases_by_groups = 406
65+
# frequent_releases_by_groups = 406 # DEPRECATED
66+
# number of events seen for a release, by issue
67+
frequent_releases_by_groups = 407
6668

6769

6870
class BaseTSDB(object):
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from __future__ import absolute_import
2+
3+
from datetime import timedelta
4+
from django.utils import timezone
5+
6+
from sentry.models import GroupRelease, Release
7+
from sentry.testutils import TestCase
8+
9+
10+
class GetOrCreateTest(TestCase):
11+
def test_simple(self):
12+
project = self.create_project()
13+
group = self.create_group(project=project)
14+
release = Release.objects.create(version='abc', project=project)
15+
16+
datetime = timezone.now()
17+
18+
grouprelease = GroupRelease.get_or_create(
19+
group=group,
20+
release=release,
21+
environment='prod',
22+
datetime=datetime,
23+
)
24+
25+
assert grouprelease.project_id == project.id
26+
assert grouprelease.group_id == group.id
27+
assert grouprelease.release_id == release.id
28+
assert grouprelease.environment == 'prod'
29+
assert grouprelease.first_seen == datetime
30+
assert grouprelease.last_seen == datetime
31+
32+
datetime_new = timezone.now() + timedelta(days=1)
33+
34+
grouprelease = GroupRelease.get_or_create(
35+
group=group,
36+
release=release,
37+
environment='prod',
38+
datetime=datetime_new,
39+
)
40+
41+
assert grouprelease.first_seen == datetime
42+
assert grouprelease.last_seen == datetime_new
43+
44+
def test_empty_env(self):
45+
project = self.create_project()
46+
group = self.create_group(project=project)
47+
release = Release.objects.create(version='abc', project=project)
48+
49+
datetime = timezone.now()
50+
51+
grouprelease = GroupRelease.get_or_create(
52+
group=group,
53+
release=release,
54+
environment=None,
55+
datetime=datetime,
56+
)
57+
58+
assert grouprelease.environment == ''

0 commit comments

Comments
 (0)