mirror of https://github.com/zulip/zulip.git
slack-integration: Block requests from Slack retries.
A Slack fail condition occurs when we don't respond with HTTP 200 within 3 seconds after Slack calls our endpoint. If this happens, Slack will retry sending the same payload. This is often triggered because we need to perform callbacks when converting messages. To avoid sending the same message multiple times, we block subsequent retry calls from Slack. This commit returns early HTTP 200 response as soon as we get any retry calls from Slack. Part of #30465.
This commit is contained in:
parent
1a36266570
commit
22d510f2a8
|
@ -299,6 +299,18 @@ class SlackWebhookTests(WebhookTestCase):
|
||||||
content_type="application/json",
|
content_type="application/json",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_block_slack_retries(self) -> None:
|
||||||
|
payload = self.get_body("message_with_normal_text")
|
||||||
|
with patch("zerver.webhooks.slack.view.check_send_webhook_message") as m:
|
||||||
|
result = self.client_post(
|
||||||
|
self.url,
|
||||||
|
payload,
|
||||||
|
headers={"X-Slack-Retry-Num": 1},
|
||||||
|
content_type="application/json",
|
||||||
|
)
|
||||||
|
self.assertFalse(m.called)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
|
||||||
class SlackLegacyWebhookTests(WebhookTestCase):
|
class SlackLegacyWebhookTests(WebhookTestCase):
|
||||||
CHANNEL_NAME = "slack"
|
CHANNEL_NAME = "slack"
|
||||||
|
|
|
@ -165,6 +165,10 @@ def handle_slack_webhook_message(
|
||||||
raise JsonableError(_("Error: channels_map_to_topics parameter other than 0 or 1"))
|
raise JsonableError(_("Error: channels_map_to_topics parameter other than 0 or 1"))
|
||||||
|
|
||||||
|
|
||||||
|
def is_retry_call_from_slack(request: HttpRequest) -> bool:
|
||||||
|
return "X-Slack-Retry-Num" in request.headers
|
||||||
|
|
||||||
|
|
||||||
@webhook_view("Slack", notify_bot_owner_on_invalid_json=False)
|
@webhook_view("Slack", notify_bot_owner_on_invalid_json=False)
|
||||||
@typed_endpoint
|
@typed_endpoint
|
||||||
def api_slack_webhook(
|
def api_slack_webhook(
|
||||||
|
@ -215,6 +219,15 @@ def api_slack_webhook(
|
||||||
)
|
)
|
||||||
return json_success(request=request, data={"challenge": challenge})
|
return json_success(request=request, data={"challenge": challenge})
|
||||||
|
|
||||||
|
# A Slack fail condition occurs when we don't respond with HTTP 200
|
||||||
|
# within 3 seconds after Slack calls our endpoint. If this happens,
|
||||||
|
# Slack will retry sending the same payload. This is often triggered
|
||||||
|
# because of we have to do two callbacks for each call. To avoid
|
||||||
|
# sending the same message multiple times, we block subsequent retry
|
||||||
|
# calls from Slack.
|
||||||
|
if is_retry_call_from_slack(request):
|
||||||
|
return json_success(request)
|
||||||
|
|
||||||
# Prevent any Zulip messages sent through the Slack Bridge from looping
|
# Prevent any Zulip messages sent through the Slack Bridge from looping
|
||||||
# back here.
|
# back here.
|
||||||
if is_zulip_slack_bridge_bot_message(payload):
|
if is_zulip_slack_bridge_bot_message(payload):
|
||||||
|
|
Loading…
Reference in New Issue