Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Slack error handling #3000

Merged
merged 13 commits into from
Sep 12, 2023
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Notify user via Slack/mobile push-notification when their shift swap request is taken by @joeyorlando ([#2992](https://github.com/grafana/oncall/pull/2992))

### Changed

- Improve Slack error handling by @vadimkerr ([#3000](https://github.com/grafana/oncall/pull/3000))

### Fixed

- Avoid task retries because of missing AlertGroupLogRecord on send_alert_group_signal ([#3001](https://github.com/grafana/oncall/pull/3001))
Expand Down
23 changes: 14 additions & 9 deletions engine/apps/alerts/tasks/notify_ical_schedule_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
from django.utils import timezone

from apps.schedules.ical_utils import calculate_shift_diff, parse_event_uid
from apps.slack.client import SlackAPIException, SlackAPITokenException, SlackClientWithErrorHandling
from apps.slack.client import SlackClient
from apps.slack.errors import (
SlackAPIChannelArchivedError,
SlackAPIChannelNotFoundError,
SlackAPIInvalidAuthError,
SlackAPITokenError,
)
from apps.slack.scenarios import scenario_step
from common.custom_celery_tasks import shared_dedicated_queue_retry_task

Expand Down Expand Up @@ -146,7 +152,7 @@ def notify_ical_schedule_shift(schedule_pk):
if len(new_shifts) > 0 or schedule.empty_oncall:
task_logger.info(f"new_shifts: {new_shifts}")
if schedule.notify_oncall_shift_freq != OnCallSchedule.NotifyOnCallShiftFreq.NEVER:
slack_client = SlackClientWithErrorHandling(schedule.organization.slack_team_identity.bot_access_token)
slack_client = SlackClient(schedule.organization.slack_team_identity)
step = scenario_step.ScenarioStep.get_step("schedules", "EditScheduleShiftNotifyStep")
report_blocks = step.get_report_blocks_ical(new_shifts, upcoming_shifts, schedule, schedule.empty_oncall)

Expand All @@ -156,11 +162,10 @@ def notify_ical_schedule_shift(schedule_pk):
blocks=report_blocks,
text=f"On-call shift for schedule {schedule.name} has changed",
)
except SlackAPITokenException:
except (
SlackAPITokenError,
SlackAPIChannelNotFoundError,
SlackAPIChannelArchivedError,
SlackAPIInvalidAuthError,
):
pass
except SlackAPIException as e:
expected_exceptions = ["channel_not_found", "is_archived", "invalid_auth"]
if e.response["error"] in expected_exceptions:
print(e)
else:
raise e
22 changes: 11 additions & 11 deletions engine/apps/alerts/tests/test_notify_ical_schedule_shift.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_next_shift_notification_long_shifts(

with patch("apps.alerts.tasks.notify_ical_schedule_shift.datetime", Mock(wraps=datetime)) as mock_datetime:
mock_datetime.datetime.now.return_value = datetime.datetime(2021, 9, 29, 12, 0, tzinfo=pytz.UTC)
with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(ical_schedule.pk)

slack_blocks = mock_slack_api_call.call_args_list[0][1]["blocks"]
Expand Down Expand Up @@ -204,7 +204,7 @@ def test_overrides_changes_no_current_no_triggering_notification(
schedule.prev_ical_file_overrides = ical_before
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -252,7 +252,7 @@ def test_no_changes_no_triggering_notification(
schedule.empty_oncall = False
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -300,7 +300,7 @@ def test_current_shift_changes_trigger_notification(
schedule.empty_oncall = False
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert mock_slack_api_call.called
Expand Down Expand Up @@ -364,7 +364,7 @@ def test_current_shift_changes_swap_split(
schedule.empty_oncall = False
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

text_block = mock_slack_api_call.call_args_list[0][1]["blocks"][1]["text"]["text"]
Expand Down Expand Up @@ -433,7 +433,7 @@ def test_next_shift_changes_no_triggering_notification(
on_call_shift_2.add_rolling_users([[user2]])
schedule.refresh_ical_file()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -500,7 +500,7 @@ def test_lower_priority_changes_no_triggering_notification(
on_call_shift_2.add_rolling_users([[user2]])
schedule.refresh_ical_file()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -630,7 +630,7 @@ def test_vtimezone_changes_no_triggering_notification(
schedule.cached_ical_file_primary = ical_after
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -687,7 +687,7 @@ def test_no_changes_no_triggering_notification_from_old_to_new_task_version(
schedule.empty_oncall = False
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -749,7 +749,7 @@ def test_current_shift_changes_trigger_notification_from_old_to_new_task_version
on_call_shift.add_rolling_users([[user2]])
schedule.refresh_ical_file()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert mock_slack_api_call.called
Expand Down Expand Up @@ -814,7 +814,7 @@ def test_next_shift_notification_long_and_short_shifts(
schedule.empty_oncall = False
schedule.save()

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_ical_schedule_shift(schedule.pk)

assert mock_slack_api_call.called
Expand Down
4 changes: 2 additions & 2 deletions engine/apps/api/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
from django.utils import timezone

from apps.slack.client import SlackClientWithErrorHandling
from apps.slack.client import SlackClient
from apps.slack.scenarios.distribute_alerts import AlertShootingStep


Expand All @@ -20,7 +20,7 @@ def _mock_api_call(*args, **kwargs):
"team": {"name": "TEST_SLACK_TEAM_NAME"},
}

monkeypatch.setattr(SlackClientWithErrorHandling, "api_call", _mock_api_call)
monkeypatch.setattr(SlackClient, "api_call", _mock_api_call)


@pytest.fixture()
Expand Down
7 changes: 4 additions & 3 deletions engine/apps/integrations/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from apps.alerts.models.alert_group_counter import ConcurrentUpdateError
from apps.alerts.tasks import resolve_alert_group_by_source_if_needed
from apps.slack.client import SlackAPIException, SlackClientWithErrorHandling
from apps.slack.client import SlackClient
from apps.slack.errors import SlackAPIError
from common.custom_celery_tasks import shared_dedicated_queue_retry_task
from common.custom_celery_tasks.create_alert_base_task import CreateAlertBaseTask

Expand Down Expand Up @@ -157,7 +158,7 @@ def notify_about_integration_ratelimit_in_slack(organization_id, text, **kwargs)
slack_team_identity = organization.slack_team_identity
if slack_team_identity is not None:
try:
sc = SlackClientWithErrorHandling(slack_team_identity.bot_access_token)
sc = SlackClient(slack_team_identity)
sc.chat_postMessage(channel=organization.general_log_channel_id, text=text, team=slack_team_identity)
except SlackAPIException as e:
except SlackAPIError as e:
logger.warning(f"Slack exception {e} while sending message for organization {organization_id}")
7 changes: 4 additions & 3 deletions engine/apps/public_api/helpers.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from apps.public_api.constants import VALID_DATE_FOR_DELETE_INCIDENT
from apps.slack.client import SlackAPITokenException, SlackClientWithErrorHandling
from apps.slack.client import SlackClient
from apps.slack.errors import SlackAPITokenError


def team_has_slack_token_for_deleting(alert_group):
if alert_group.slack_message and alert_group.slack_message.slack_team_identity:
sc = SlackClientWithErrorHandling(alert_group.slack_message.slack_team_identity.bot_access_token)
sc = SlackClient(alert_group.slack_message.slack_team_identity)
try:
sc.auth_test()
except SlackAPITokenException:
except SlackAPITokenError:
return False
return True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def test_followup_offsets():
assert ShiftSwapRequest.FOLLOWUP_OFFSETS[idx] > FOLLOWUP_WINDOW


@patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage")
@patch("apps.slack.client.SlackClient.chat_postMessage")
@pytest.mark.django_db
def test_send_shift_swap_request_followup(mock_slack_chat_post_message, shift_swap_request_test_setup):
shift_swap_request = shift_swap_request_test_setup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def test_no_empty_shifts_no_triggering_notification(

empty_shifts_report_sent_at = schedule.empty_shifts_report_sent_at

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_empty_shifts_in_schedule(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -97,7 +97,7 @@ def test_empty_shifts_trigger_notification(

empty_shifts_report_sent_at = schedule.empty_shifts_report_sent_at

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_empty_shifts_in_schedule(schedule.pk)

assert mock_slack_api_call.called
Expand Down Expand Up @@ -160,7 +160,7 @@ def test_empty_non_empty_shifts_trigger_notification(

empty_shifts_report_sent_at = schedule.empty_shifts_report_sent_at

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_empty_shifts_in_schedule(schedule.pk)

assert mock_slack_api_call.called
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_no_gaps_no_triggering_notification(

gaps_report_sent_at = schedule.gaps_report_sent_at

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_gaps_in_schedule(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -113,7 +113,7 @@ def test_gaps_in_the_past_no_triggering_notification(

gaps_report_sent_at = schedule.gaps_report_sent_at

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_gaps_in_schedule(schedule.pk)

assert not mock_slack_api_call.called
Expand Down Expand Up @@ -165,7 +165,7 @@ def test_gaps_now_trigger_notification(

assert schedule.has_gaps is False

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_gaps_in_schedule(schedule.pk)

assert mock_slack_api_call.called
Expand Down Expand Up @@ -219,7 +219,7 @@ def test_gaps_near_future_trigger_notification(

assert schedule.has_gaps is False

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_gaps_in_schedule(schedule.pk)

assert mock_slack_api_call.called
Expand Down Expand Up @@ -271,7 +271,7 @@ def test_gaps_later_than_7_days_no_triggering_notification(

gaps_report_sent_at = schedule.gaps_report_sent_at

with patch("apps.slack.client.SlackClientWithErrorHandling.chat_postMessage") as mock_slack_api_call:
with patch("apps.slack.client.SlackClient.chat_postMessage") as mock_slack_api_call:
notify_about_gaps_in_schedule(schedule.pk)

assert not mock_slack_api_call.called
Expand Down
Loading
Loading