Add transaction block and callbacks when triggering tasks (#3779)

Related to https://github.com/grafana/oncall/issues/3729
This commit is contained in:
Matias Bordese 2024-01-31 11:26:14 -03:00 committed by GitHub
parent 16ce0136f3
commit 3795c836d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 42 additions and 24 deletions

View file

@ -65,6 +65,7 @@ class AlertGroupLogRecord(models.Model):
TYPE_DELETED,
TYPE_REGISTERED, # set on creation before having an alert assigned, skip to avoid retries
TYPE_ROUTE_ASSIGNED, # set on creation before having an alert assigned, skip to avoid retries
TYPE_ACK_REMINDER_TRIGGERED, # set on acknowledged reminder, no updates to the alert group log
)
TYPES_FOR_LICENCE_CALCULATION = (

View file

@ -1,4 +1,5 @@
import typing
from functools import partial
from uuid import uuid4
from django.db import transaction
@ -148,22 +149,27 @@ def direct_paging(
title = _construct_title(from_user, team, users)
# create alert group if needed
if alert_group is None:
alert_group = _trigger_alert(organization, team, message, title, source_url, grafana_incident_id, from_user)
with transaction.atomic():
if alert_group is None:
alert_group = _trigger_alert(organization, team, message, title, source_url, grafana_incident_id, from_user)
for u, important in users:
alert_group.log_records.create(
type=AlertGroupLogRecord.TYPE_DIRECT_PAGING,
author=from_user,
reason=f"{from_user.username} paged user {u.username}",
step_specific_info={
"user": u.public_primary_key,
"important": important,
},
)
notify_user_task.apply_async(
(u.pk, alert_group.pk), {"important": important, "notify_even_acknowledged": True, "notify_anyway": True}
)
for u, important in users:
alert_group.log_records.create(
type=AlertGroupLogRecord.TYPE_DIRECT_PAGING,
author=from_user,
reason=f"{from_user.username} paged user {u.username}",
step_specific_info={
"user": u.public_primary_key,
"important": important,
},
)
transaction.on_commit(
partial(
notify_user_task.apply_async,
(u.pk, alert_group.pk),
{"important": important, "notify_even_acknowledged": True, "notify_anyway": True},
)
)
return alert_group

View file

@ -72,10 +72,11 @@ def acknowledge_reminder_task(alert_group_pk: int, unacknowledge_process_id: str
(alert_group.pk, unacknowledge_process_id), countdown=acknowledge_reminder_timeout
)
log_record = alert_group.log_records.create(
type=AlertGroupLogRecord.TYPE_ACK_REMINDER_TRIGGERED, author=alert_group.acknowledged_by_user
)
transaction.on_commit(partial(send_alert_group_signal.delay, log_record.pk))
with transaction.atomic():
log_record = alert_group.log_records.create(
type=AlertGroupLogRecord.TYPE_ACK_REMINDER_TRIGGERED, author=alert_group.acknowledged_by_user
)
transaction.on_commit(partial(send_alert_group_signal.delay, log_record.pk))
@shared_dedicated_queue_retry_task(autoretry_for=(Exception,), retry_backoff=True, max_retries=MAX_RETRIES)

View file

@ -159,12 +159,19 @@ def test_acknowledge_reminder_task_skip(
@patch.object(acknowledge_reminder_task, "apply_async")
@pytest.mark.django_db
def test_acknowledge_reminder_task_reschedules_itself(
mock_acknowledge_reminder_task, mock_unacknowledge_timeout_task, ack_reminder_test_setup
mock_acknowledge_reminder_task,
mock_unacknowledge_timeout_task,
ack_reminder_test_setup,
django_capture_on_commit_callbacks,
):
organization, alert_group, user = ack_reminder_test_setup(
unacknowledge_timeout=Organization.UNACKNOWLEDGE_TIMEOUT_NEVER
)
acknowledge_reminder_task(alert_group.pk, TASK_ID)
with django_capture_on_commit_callbacks(execute=True) as callbacks:
acknowledge_reminder_task(alert_group.pk, TASK_ID)
# send_alert_group_signal task is queued after commit
assert len(callbacks) == 1
mock_unacknowledge_timeout_task.assert_not_called()
mock_acknowledge_reminder_task.assert_called_once_with(

View file

@ -54,15 +54,16 @@ def test_user_is_oncall(make_organization, make_user_for_organization, make_sche
@pytest.mark.django_db
def test_direct_paging_user(make_organization, make_user_for_organization):
def test_direct_paging_user(make_organization, make_user_for_organization, django_capture_on_commit_callbacks):
organization = make_organization()
user = make_user_for_organization(organization)
other_user = make_user_for_organization(organization)
from_user = make_user_for_organization(organization)
msg = "Fire"
with patch("apps.alerts.paging.notify_user_task") as notify_task:
direct_paging(organization, from_user, msg, users=[(user, False), (other_user, True)])
with django_capture_on_commit_callbacks(execute=True) as callbacks:
with patch("apps.alerts.paging.notify_user_task") as notify_task:
direct_paging(organization, from_user, msg, users=[(user, False), (other_user, True)])
# alert group created
alert_groups = AlertGroup.objects.all()
@ -73,6 +74,8 @@ def test_direct_paging_user(make_organization, make_user_for_organization):
assert alert.title == f"{from_user.username} is paging {user.username} and {other_user.username} to join escalation"
assert alert.message == msg
# callbacks: distribute_alert + 2 notify_user tasks
assert len(callbacks) == 3
# notifications sent
for u, important in ((user, False), (other_user, True)):
assert notify_task.apply_async.called_with(