Skip to content

Commit 518578b

Browse files
authored
feat(relay): Tag project config invalidations with option (#95423)
In cases where a project config is invalidated because a project option was set or deleted, we now add a tag `trigger_details`/`update_reason_details` to the Sentry scope and the metrics for the invalidation, respectively. Ref INGEST-444.
1 parent b48b90e commit 518578b

File tree

3 files changed

+37
-10
lines changed

3 files changed

+37
-10
lines changed

src/sentry/models/options/project_option.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def get_value(
115115

116116
def unset_value(self, project: Project, key: str) -> None:
117117
self.filter(project=project, key=key).delete()
118-
self.reload_cache(project.id, "projectoption.unset_value")
118+
self.reload_cache(project.id, "projectoption.unset_value", key)
119119

120120
def set_value(self, project: int | Project, key: str, value: Any) -> bool:
121121
if isinstance(project, models.Model):
@@ -126,7 +126,7 @@ def set_value(self, project: int | Project, key: str, value: Any) -> bool:
126126
inst, created = self.create_or_update(
127127
project_id=project_id, key=key, values={"value": value}
128128
)
129-
self.reload_cache(project_id, "projectoption.set_value")
129+
self.reload_cache(project_id, "projectoption.set_value", key)
130130

131131
return created or inst > 0
132132

@@ -146,22 +146,26 @@ def get_all_values(self, project: Project | int) -> Mapping[str, Any]:
146146

147147
return self._option_cache.get(cache_key, {})
148148

149-
def reload_cache(self, project_id: int, update_reason: str) -> Mapping[str, Any]:
149+
def reload_cache(
150+
self, project_id: int, update_reason: str, option_key: str | None = None
151+
) -> Mapping[str, Any]:
150152
from sentry.tasks.relay import schedule_invalidate_project_config
151153

152154
if update_reason != "projectoption.get_all_values":
153-
schedule_invalidate_project_config(project_id=project_id, trigger=update_reason)
155+
schedule_invalidate_project_config(
156+
project_id=project_id, trigger=update_reason, trigger_details=option_key
157+
)
154158
cache_key = self._make_key(project_id)
155159
result = {i.key: i.value for i in self.filter(project=project_id)}
156160
cache.set(cache_key, result)
157161
self._option_cache[cache_key] = result
158162
return result
159163

160164
def post_save(self, *, instance: ProjectOption, created: bool, **kwargs: object) -> None:
161-
self.reload_cache(instance.project_id, "projectoption.post_save")
165+
self.reload_cache(instance.project_id, "projectoption.post_save", option_key=instance.key)
162166

163167
def post_delete(self, instance: ProjectOption, **kwargs: Any) -> None:
164-
self.reload_cache(instance.project_id, "projectoption.post_delete")
168+
self.reload_cache(instance.project_id, "projectoption.post_delete", option_key=instance.key)
165169

166170
def isset(self, project: Project, key: str) -> bool:
167171
return self.get_value(project, key, default=Ellipsis) is not Ellipsis

src/sentry/tasks/relay.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,12 @@ def compute_projectkey_config(key):
211211
),
212212
)
213213
def invalidate_project_config(
214-
organization_id=None, project_id=None, public_key=None, trigger="invalidated", **kwargs
214+
organization_id=None,
215+
project_id=None,
216+
public_key=None,
217+
trigger="invalidated",
218+
trigger_details=None,
219+
**kwargs,
215220
):
216221
"""Task which re-computes an invalidated project config.
217222
@@ -247,6 +252,7 @@ def invalidate_project_config(
247252
if public_key:
248253
sentry_sdk.set_tag("public_key", public_key)
249254
sentry_sdk.set_tag("trigger", trigger)
255+
sentry_sdk.set_tag("trigger_details", trigger_details)
250256
sentry_sdk.set_context("kwargs", kwargs)
251257

252258
updated_configs = compute_configs(
@@ -259,6 +265,7 @@ def invalidate_project_config(
259265
def schedule_invalidate_project_config(
260266
*,
261267
trigger,
268+
trigger_details=None,
262269
organization_id=None,
263270
project_id=None,
264271
public_key=None,
@@ -291,6 +298,8 @@ def schedule_invalidate_project_config(
291298
the project config task is executed immediately.
292299
293300
:param trigger: The reason for the invalidation. This is used to tag metrics.
301+
:param trigger_details: Additional information about what triggered the invalidation.
302+
This is used to tag metrics.
294303
:param organization_id: Invalidates all project keys for all projects in an organization.
295304
:param project_id: Invalidates all project keys for a project.
296305
:param public_key: Invalidate a single public key.
@@ -317,6 +326,7 @@ def schedule_invalidate_project_config(
317326
transaction.on_commit(
318327
lambda: _schedule_invalidate_project_config(
319328
trigger=trigger,
329+
trigger_details=trigger_details,
320330
organization_id=organization_id,
321331
project_id=project_id,
322332
public_key=public_key,
@@ -329,6 +339,7 @@ def schedule_invalidate_project_config(
329339
def _schedule_invalidate_project_config(
330340
*,
331341
trigger,
342+
trigger_details=None,
332343
organization_id=None,
333344
project_id=None,
334345
public_key=None,
@@ -377,7 +388,11 @@ def _schedule_invalidate_project_config(
377388

378389
metrics.incr(
379390
"relay.projectconfig_cache.scheduled",
380-
tags={"update_reason": trigger, "task": "invalidation"},
391+
tags={
392+
"update_reason": trigger,
393+
"update_reason_details": trigger_details,
394+
"task": "invalidation",
395+
},
381396
)
382397

383398
invalidate_project_config.apply_async(
@@ -387,6 +402,7 @@ def _schedule_invalidate_project_config(
387402
"organization_id": organization_id,
388403
"public_key": public_key,
389404
"trigger": trigger,
405+
"trigger_details": trigger_details,
390406
},
391407
)
392408

tests/sentry/tasks/test_relay.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,21 +388,27 @@ def apply_async(args=None, kwargs=None, countdown=None):
388388
invalidation_debounce_cache.mark_task_done(
389389
public_key=None, project_id=None, organization_id=default_organization.id
390390
)
391-
schedule_invalidate_project_config(organization_id=default_organization.id, trigger="test")
392-
schedule_invalidate_project_config(organization_id=default_organization.id, trigger="test")
391+
schedule_invalidate_project_config(
392+
organization_id=default_organization.id, trigger="test", trigger_details="more test"
393+
)
394+
schedule_invalidate_project_config(
395+
organization_id=default_organization.id, trigger="test", trigger_details="more test"
396+
)
393397

394398
assert tasks == [
395399
{
396400
"project_id": default_project.id,
397401
"organization_id": None,
398402
"public_key": None,
399403
"trigger": "test",
404+
"trigger_details": None,
400405
},
401406
{
402407
"project_id": None,
403408
"organization_id": default_organization.id,
404409
"public_key": None,
405410
"trigger": "test",
411+
"trigger_details": "more test",
406412
},
407413
]
408414

@@ -473,6 +479,7 @@ def test_project_config_invalidations_after_commit(
473479
assert schedule_inner.call_count == 1
474480
assert schedule_inner.call_args == call(
475481
trigger="test",
482+
trigger_details=None,
476483
organization_id=None,
477484
project_id=default_project.id,
478485
public_key=None,

0 commit comments

Comments
 (0)