Skip to content

Commit db1b82d

Browse files
Add retries to slack webhook delivery
1 parent 40dd5ec commit db1b82d

File tree

2 files changed

+23
-10
lines changed

2 files changed

+23
-10
lines changed

src/meshapi/tests/test_slack_notification.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ def test_slack_notification_for_name_change_no_env_var(self, requests_mocker):
269269

270270
@requests_mock.Mocker()
271271
@patch("meshapi.util.admin_notifications.SLACK_ADMIN_NOTIFICATIONS_WEBHOOK_URL", "https://mock-slack-url")
272+
@patch("meshapi.util.admin_notifications.SLACK_ADMIN_NOTIFICATIONS_RETRY_COUNT", 2)
272273
def test_slack_notification_for_name_change_slack_failure(self, requests_mocker):
273274
member = Member(
274275
name="Stacy Maidenname",
@@ -293,6 +294,7 @@ def test_slack_notification_for_name_change_slack_failure(self, requests_mocker)
293294
)
294295

295296
self.assertEqual(requests_mocker.request_history[0].url, "https://mock-slack-url/")
297+
self.assertEqual(len(requests_mocker.request_history), 3)
296298

297299
@requests_mock.Mocker()
298300
@patch("meshapi.util.admin_notifications.SLACK_ADMIN_NOTIFICATIONS_WEBHOOK_URL", "https://mock-slack-url")

src/meshapi/util/admin_notifications.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import logging
33
import os
4+
import time
45
from typing import Optional, Sequence, Type
56

67
import requests
@@ -13,6 +14,8 @@
1314
SLACK_ADMIN_NOTIFICATIONS_WEBHOOK_URL = os.environ.get("SLACK_ADMIN_NOTIFICATIONS_WEBHOOK_URL")
1415
SITE_BASE_URL = os.environ.get("SITE_BASE_URL")
1516

17+
SLACK_ADMIN_NOTIFICATIONS_RETRY_COUNT = int(os.environ.get("SLACK_ADMIN_NOTIFICATIONS_RETRY_COUNT", 3))
18+
1619

1720
def escape_slack_text(text: str) -> str:
1821
return text.replace("↔", "<->").replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")
@@ -69,13 +72,21 @@ def notify_admins(
6972
)
7073
return
7174

72-
response = requests.post(SLACK_ADMIN_NOTIFICATIONS_WEBHOOK_URL, json=slack_message)
73-
74-
if raise_exception_on_failure:
75-
response.raise_for_status()
76-
elif response.status_code != 200:
77-
logging.error(
78-
f"Got HTTP {response.status_code} while sending slack notification to slack admin. "
79-
f"HTTP response was {response.text}. Unable to notify admins of "
80-
f"the following message: {slack_message}"
81-
)
75+
for i in range(0, SLACK_ADMIN_NOTIFICATIONS_RETRY_COUNT + 1):
76+
response = requests.post(SLACK_ADMIN_NOTIFICATIONS_WEBHOOK_URL, json=slack_message)
77+
try:
78+
response.raise_for_status()
79+
return
80+
except requests.exceptions.RequestException as e:
81+
if i == SLACK_ADMIN_NOTIFICATIONS_RETRY_COUNT:
82+
if raise_exception_on_failure:
83+
raise e
84+
else:
85+
logging.error(
86+
f"Got HTTP {response.status_code} while sending slack notification to slack admin. "
87+
f"HTTP response was {response.text}. Unable to notify admins of "
88+
f"the following message: {slack_message}"
89+
)
90+
else:
91+
# Exponential backoff to try to avoid triggering Slack's rate limiting logic
92+
time.sleep(2**i)

0 commit comments

Comments
 (0)