Skip to content

Commit 8a4122a

Browse files
author
David Wang
authored
ref(crons): Add # of broken monitors to email subject (#69006)
Add # of broken monitors to this email subject This was in direct response to feedback received that the previous subject line made this email feel like a marketing campaign (encouraging the user to instrument their crons with Sentry) rather than an alert telling the user that certain things were broken. fixes: https://github.com/getsentry/team-crons/issues/174
1 parent ebb08ca commit 8a4122a

File tree

2 files changed

+73
-12
lines changed

2 files changed

+73
-12
lines changed

src/sentry/monitors/tasks/detect_broken_monitor_envs.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ def detect_broken_monitor_envs_for_org(org_id: int):
238238
"view_monitors_link": generate_monitor_overview_url(organization),
239239
}
240240
message = MessageBuilder(
241-
subject="Your Cron Monitors Aren't Working",
241+
subject="{} of your Cron Monitors {} working".format(
242+
len(broken_monitors), "isn't" if len(broken_monitors) == 1 else "aren't"
243+
),
242244
template="sentry/emails/crons/broken-monitors.txt",
243245
html_template="sentry/emails/crons/broken-monitors.html",
244246
type="crons.broken_monitors",
@@ -252,7 +254,9 @@ def detect_broken_monitor_envs_for_org(org_id: int):
252254
"view_monitors_link": generate_monitor_overview_url(organization),
253255
}
254256
message = MessageBuilder(
255-
subject="Your Cron Monitors have been muted",
257+
subject="{} of your Cron Monitors {} been muted".format(
258+
len(muted_monitors), "has" if len(muted_monitors) == 1 else "have"
259+
),
256260
template="sentry/emails/crons/muted-monitors.txt",
257261
html_template="sentry/emails/crons/muted-monitors.html",
258262
type="crons.muted_monitors",

tests/sentry/monitors/tasks/test_detect_broken_monitor_envs.py

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,23 @@ def test_sends_emails_to_all_users_across_orgs(self, mock_now, builder):
211211
project_id=second_project.id,
212212
environment_id=second_env.id,
213213
)
214+
third_monitor, third_monitor_environment = self.create_monitor_and_env(
215+
name="third monitor",
216+
organization_id=second_org.id,
217+
project_id=second_project.id,
218+
environment_id=second_env.id,
219+
)
214220

215221
self.create_incident_for_monitor_env(monitor, monitor_environment)
216222
self.create_incident_for_monitor_env(second_monitor, second_monitor_environment)
223+
self.create_incident_for_monitor_env(third_monitor, third_monitor_environment)
217224

218225
detect_broken_monitor_envs()
219226
broken_detections = MonitorEnvBrokenDetection.objects.all()
220-
assert len(broken_detections) == 2
227+
assert len(broken_detections) == 3
221228
assert broken_detections[0].user_notified_timestamp == now
222229
assert broken_detections[1].user_notified_timestamp == now
230+
assert broken_detections[2].user_notified_timestamp == now
223231
# should build 3 emails, 2 for self.user from the 2 orgs, and 1 for second_user
224232
expected_contexts = [
225233
{
@@ -238,7 +246,12 @@ def test_sends_emails_to_all_users_across_orgs(self, mock_now, builder):
238246
second_monitor.slug,
239247
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{second_monitor.slug}/?environment={second_env.name}",
240248
timezone.now() - timedelta(days=14),
241-
)
249+
),
250+
(
251+
third_monitor.slug,
252+
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{third_monitor.slug}/?environment={second_env.name}",
253+
timezone.now() - timedelta(days=14),
254+
),
242255
],
243256
"view_monitors_link": f"http://testserver/organizations/{second_org.slug}/crons/",
244257
},
@@ -248,24 +261,34 @@ def test_sends_emails_to_all_users_across_orgs(self, mock_now, builder):
248261
second_monitor.slug,
249262
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{second_monitor.slug}/?environment={second_env.name}",
250263
timezone.now() - timedelta(days=14),
251-
)
264+
),
265+
(
266+
third_monitor.slug,
267+
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{third_monitor.slug}/?environment={second_env.name}",
268+
timezone.now() - timedelta(days=14),
269+
),
252270
],
253271
"view_monitors_link": f"http://testserver/organizations/{second_org.slug}/crons/",
254272
},
255273
]
274+
expected_subjects = [
275+
"1 of your Cron Monitors isn't working",
276+
"2 of your Cron Monitors aren't working",
277+
"2 of your Cron Monitors aren't working",
278+
]
256279

257280
builder.assert_has_calls(
258281
[
259282
call(
260283
**{
261-
"subject": "Your Cron Monitors Aren't Working",
284+
"subject": subject,
262285
"template": "sentry/emails/crons/broken-monitors.txt",
263286
"html_template": "sentry/emails/crons/broken-monitors.html",
264287
"type": "crons.broken_monitors",
265288
"context": context,
266289
}
267290
)
268-
for context in expected_contexts[:1]
291+
for subject, context in zip(expected_subjects, expected_contexts)
269292
],
270293
any_order=True,
271294
)
@@ -291,11 +314,20 @@ def test_disables_environments_and_sends_email(self, mock_now, builder):
291314
project_id=second_project.id,
292315
environment_id=second_env.id,
293316
)
317+
third_monitor, third_monitor_environment = self.create_monitor_and_env(
318+
name="third monitor",
319+
organization_id=second_org.id,
320+
project_id=second_project.id,
321+
environment_id=second_env.id,
322+
)
294323

295324
incident = self.create_incident_for_monitor_env(monitor, monitor_environment)
296325
second_incident = self.create_incident_for_monitor_env(
297326
second_monitor, second_monitor_environment
298327
)
328+
third_incident = self.create_incident_for_monitor_env(
329+
third_monitor, third_monitor_environment
330+
)
299331

300332
broken_detection = MonitorEnvBrokenDetection.objects.create(
301333
monitor_incident=incident,
@@ -307,19 +339,29 @@ def test_disables_environments_and_sends_email(self, mock_now, builder):
307339
detection_timestamp=now - timedelta(days=14),
308340
user_notified_timestamp=now - timedelta(days=14),
309341
)
342+
third_broken_detection = MonitorEnvBrokenDetection.objects.create(
343+
monitor_incident=third_incident,
344+
detection_timestamp=now - timedelta(days=14),
345+
user_notified_timestamp=now - timedelta(days=14),
346+
)
310347

311348
detect_broken_monitor_envs()
312349

313350
# should have the two monitor environments as muted
314351
monitor_environment.refresh_from_db()
315352
second_monitor_environment.refresh_from_db()
353+
third_monitor_environment.refresh_from_db()
316354
assert monitor_environment.is_muted
317355
assert second_monitor_environment.is_muted
356+
assert third_monitor_environment.is_muted
318357

319358
broken_detection.refresh_from_db()
320359
second_broken_detection.refresh_from_db()
360+
third_broken_detection.refresh_from_db()
361+
321362
assert broken_detection.env_muted_timestamp == now
322363
assert second_broken_detection.env_muted_timestamp == now
364+
assert third_broken_detection.env_muted_timestamp == now
323365

324366
# should build 3 emails, 2 for self.user from the 2 orgs, and 1 for second_user
325367
expected_contexts = [
@@ -339,7 +381,12 @@ def test_disables_environments_and_sends_email(self, mock_now, builder):
339381
second_monitor.slug,
340382
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{second_monitor.slug}/?environment={second_env.name}",
341383
timezone.now() - timedelta(days=14),
342-
)
384+
),
385+
(
386+
third_monitor.slug,
387+
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{third_monitor.slug}/?environment={second_env.name}",
388+
timezone.now() - timedelta(days=14),
389+
),
343390
],
344391
"view_monitors_link": f"http://testserver/organizations/{second_org.slug}/crons/",
345392
},
@@ -349,24 +396,34 @@ def test_disables_environments_and_sends_email(self, mock_now, builder):
349396
second_monitor.slug,
350397
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{second_monitor.slug}/?environment={second_env.name}",
351398
timezone.now() - timedelta(days=14),
352-
)
399+
),
400+
(
401+
third_monitor.slug,
402+
f"http://testserver/organizations/{second_org.slug}/crons/{second_project.slug}/{third_monitor.slug}/?environment={second_env.name}",
403+
timezone.now() - timedelta(days=14),
404+
),
353405
],
354406
"view_monitors_link": f"http://testserver/organizations/{second_org.slug}/crons/",
355407
},
356408
]
409+
expected_subjects = [
410+
"1 of your Cron Monitors has been muted",
411+
"2 of your Cron Monitors have been muted",
412+
"2 of your Cron Monitors have been muted",
413+
]
357414

358415
builder.assert_has_calls(
359416
[
360417
call(
361418
**{
362-
"subject": "Your Cron Monitors have been muted",
419+
"subject": subject,
363420
"template": "sentry/emails/crons/muted-monitors.txt",
364421
"html_template": "sentry/emails/crons/muted-monitors.html",
365422
"type": "crons.muted_monitors",
366423
"context": context,
367424
}
368425
)
369-
for context in expected_contexts
426+
for subject, context in zip(expected_subjects, expected_contexts)
370427
],
371428
any_order=True,
372429
)
@@ -451,7 +508,7 @@ def test_disables_corrects_environments_and_sends_email(self, mock_now, builder)
451508
[
452509
call(
453510
**{
454-
"subject": "Your Cron Monitors have been muted",
511+
"subject": "1 of your Cron Monitors has been muted",
455512
"template": "sentry/emails/crons/muted-monitors.txt",
456513
"html_template": "sentry/emails/crons/muted-monitors.html",
457514
"type": "crons.muted_monitors",

0 commit comments

Comments
 (0)