Browse Source

perf: Experimentally use orjson in Slack integration (#69409)

This adds an option `"integrations.slack.enable-orjson"` to enable
`orjson` for json parsing (ETA: and dumping) in the slack integration.

Ref: https://github.com/getsentry/sentry/issues/68903
Sebastian Zivota 10 months ago
parent
commit
1766e917cd

+ 9 - 3
src/sentry/integrations/slack/actions/notification.py

@@ -97,7 +97,9 @@ class SlackNotifyServiceAction(IntegrationEventAction):
             if payload_blocks := blocks.get("blocks"):
                 payload = {
                     "text": blocks.get("text"),
-                    "blocks": json.dumps(payload_blocks),
+                    "blocks": json.dumps_experimental(
+                        "integrations.slack.enable-orjson", payload_blocks
+                    ),
                     "channel": channel,
                     "unfurl_links": False,
                     "unfurl_media": False,
@@ -180,7 +182,9 @@ class SlackNotifyServiceAction(IntegrationEventAction):
                     "channel_name": self.get_option("channel"),
                 }
                 # temporarily log the payload so we can debug message failures
-                log_params["payload"] = json.dumps(payload)
+                log_params["payload"] = json.dumps_experimental(
+                    "integrations.slack.enable-orjson", payload
+                )
 
                 self.logger.info(
                     "rule.fail.slack_post",
@@ -250,7 +254,9 @@ class SlackNotifyServiceAction(IntegrationEventAction):
         blocks = SlackRuleSaveEditMessageBuilder(rule=rule, new=new, changed=changed).build()
         payload = {
             "text": blocks.get("text"),
-            "blocks": json.dumps(blocks.get("blocks")),
+            "blocks": json.dumps_experimental(
+                "integrations.slack.enable-orjson", blocks.get("blocks")
+            ),
             "channel": channel,
             "unfurl_links": False,
             "unfurl_media": False,

+ 1 - 1
src/sentry/integrations/slack/message_builder/issues.py

@@ -687,6 +687,6 @@ class SlackIssuesMessageBuilder(BlockSlackMessageBuilder):
         return self._build_blocks(
             *blocks,
             fallback_text=self.build_fallback_text(obj, project.slug),
-            block_id=json.dumps(block_id),
+            block_id=json.dumps_experimental("integrations.slack.enable-orjson", block_id),
             skip_fallback=self.skip_fallback,
         )

+ 5 - 1
src/sentry/integrations/slack/message_builder/notifications/base.py

@@ -33,7 +33,11 @@ class SlackNotificationsMessageBuilder(BlockSlackMessageBuilder):
             self.recipient, ExternalProviders.SLACK
         )
         actions = self.notification.get_message_actions(self.recipient, ExternalProviders.SLACK)
-        callback_id = json.dumps(callback_id_raw) if callback_id_raw else None
+        callback_id = (
+            json.dumps_experimental("integrations.slack.enable-orjson", callback_id_raw)
+            if callback_id_raw
+            else None
+        )
 
         first_block_text = ""
         if title_link:

+ 6 - 1
src/sentry/integrations/slack/message_builder/notifications/daily_summary.py

@@ -189,7 +189,12 @@ class SlackDailySummaryMessageBuilder(SlackNotificationsMessageBuilder):
 
         text = subject
         callback_id_raw = self.notification.get_callback_data()
-        callback_id = json.dumps(callback_id_raw) if callback_id_raw else None
+        callback_id = (
+            json.dumps_experimental("integrations.slack.enable-orjson", callback_id_raw)
+            if callback_id_raw
+            else None
+        )
+
         footer = self.notification.build_notification_footer(
             self.recipient, ExternalProviders.SLACK
         )

+ 3 - 2
src/sentry/integrations/slack/message_builder/prompt.py

@@ -13,10 +13,11 @@ class SlackPromptLinkMessageBuilder(BlockSlackMessageBuilder):
 
     def build(self) -> SlackBody:
         return {
-            "blocks": json.dumps(
+            "blocks": json.dumps_experimental(
+                "integrations.slack.enable-orjson",
                 [
                     self.get_markdown_block(LINK_IDENTITY_MESSAGE),
                     self.get_action_block([("Link", self.url, "link"), ("Cancel", None, "ignore")]),
-                ]
+                ],
             )
         }

+ 4 - 2
src/sentry/integrations/slack/notifications.py

@@ -94,7 +94,7 @@ def _notify_recipient(
             "unfurl_links": False,
             "unfurl_media": False,
             "text": text if text else "",
-            "blocks": json.dumps(blocks),
+            "blocks": json.dumps_experimental("integrations.slack.enable-orjson", blocks),
         }
         callback_id = local_attachments.get("callback_id")
         if callback_id:
@@ -102,7 +102,9 @@ def _notify_recipient(
             if isinstance(callback_id, str):
                 payload["callback_id"] = callback_id
             else:
-                payload["callback_id"] = json.dumps(local_attachments.get("callback_id"))
+                payload["callback_id"] = json.dumps_experimental(
+                    "integrations.slack.enable-orjson", local_attachments.get("callback_id")
+                )
 
         post_message_task = post_message
         if SiloMode.get_current_mode() == SiloMode.CONTROL:

+ 21 - 7
src/sentry/integrations/slack/requests/action.py

@@ -37,7 +37,9 @@ class SlackActionRequest(SlackRequest):
             - is_message: did the original message have a 'message' type
         """
         if self.data.get("callback_id"):
-            return json.loads(self.data["callback_id"])
+            return json.loads_experimental(
+                "integrations.slack.enable-orjson", self.data["callback_id"]
+            )
 
         # XXX(CEO): can't really feature flag this but the block kit data is very different
 
@@ -45,19 +47,29 @@ class SlackActionRequest(SlackRequest):
         # we don't do anything with it until the user hits "Submit" but we need to handle it anyway
         if self.data["type"] == "block_actions":
             if self.data.get("view"):
-                return json.loads(self.data["view"]["private_metadata"])
+                return json.loads_experimental(
+                    "integrations.slack.enable-orjson", self.data["view"]["private_metadata"]
+                )
+
             elif self.data.get("container", {}).get(
                 "is_app_unfurl"
             ):  # for actions taken on interactive unfurls
-                return json.loads(self.data["app_unfurl"]["blocks"][0]["block_id"])
-            return json.loads(self.data["message"]["blocks"][0]["block_id"])
+                return json.loads_experimental(
+                    "integrations.slack.enable-orjson",
+                    self.data["app_unfurl"]["blocks"][0]["block_id"],
+                )
+            return json.loads_experimental(
+                "integrations.slack.enable-orjson", self.data["message"]["blocks"][0]["block_id"]
+            )
 
         if self.data["type"] == "view_submission":
-            return json.loads(self.data["view"]["private_metadata"])
+            return json.loads_experimental(
+                "integrations.slack.enable-orjson", self.data["view"]["private_metadata"]
+            )
 
         for data in self.data["message"]["blocks"]:
             if data["type"] == "section" and len(data["block_id"]) > 5:
-                return json.loads(data["block_id"])
+                return json.loads_experimental("integrations.slack.enable-orjson", data["block_id"])
                 # a bit hacky, you can only provide a block ID per block (not per entire message),
                 # and if not provided slack generates a 5 char long one. our provided block_id is at least '{issue: <issue_id>}'
                 # so we know it's longer than 5 chars
@@ -74,7 +86,9 @@ class SlackActionRequest(SlackRequest):
             raise SlackRequestError(status=status.HTTP_400_BAD_REQUEST)
 
         try:
-            self._data = json.loads(self.data["payload"])
+            self._data = json.loads_experimental(
+                "integrations.slack.enable-orjson", self.data["payload"]
+            )
         except (KeyError, IndexError, TypeError, ValueError):
             raise SlackRequestError(status=status.HTTP_400_BAD_REQUEST)
 

+ 14 - 3
src/sentry/integrations/slack/requests/options_load.py

@@ -19,8 +19,17 @@ class SlackOptionsLoadRequest(SlackRequest):
     @property
     def group_id(self) -> int:
         if self.data.get("container", {}).get("is_app_unfurl"):
-            return int(json.loads(self.data["app_unfurl"]["blocks"][0]["block_id"])["issue"])
-        return int(json.loads(self.data["message"]["blocks"][0]["block_id"])["issue"])
+            return int(
+                json.loads_experimental(
+                    "integrations.slack.enable-orjson",
+                    self.data["app_unfurl"]["blocks"][0]["block_id"],
+                )["issue"]
+            )
+        return int(
+            json.loads_experimental(
+                "integrations.slack.enable-orjson", self.data["message"]["blocks"][0]["block_id"]
+            )["issue"]
+        )
 
     @property
     def substring(self) -> str:
@@ -33,7 +42,9 @@ class SlackOptionsLoadRequest(SlackRequest):
             raise SlackRequestError(status=status.HTTP_400_BAD_REQUEST)
 
         try:
-            self._data = json.loads(self.data["payload"])
+            self._data = json.loads_experimental(
+                "integrations.slack.enable-orjson", self.data["payload"]
+            )
         except (KeyError, IndexError, TypeError, ValueError):
             raise SlackRequestError(status=status.HTTP_400_BAD_REQUEST)
 

+ 3 - 1
src/sentry/integrations/slack/service.py

@@ -201,7 +201,9 @@ class SlackService:
         )
         payload.update(slack_payload)
         # TODO (Yash): Users should not have to remember to do this, interface should handle serializing the field
-        payload["blocks"] = json.dumps(payload.get("blocks"))
+        payload["blocks"] = json.dumps_experimental(
+            "integrations.slack.enable-orjson", payload.get("blocks")
+        )
         try:
             client.post("/chat.postMessage", data=payload, timeout=5)
         except Exception as err:

+ 1 - 1
src/sentry/integrations/slack/utils/notifications.py

@@ -63,7 +63,7 @@ def send_incident_alert_notification(
     payload = {
         "channel": channel,
         "text": text,
-        "attachments": json.dumps([blocks]),
+        "attachments": json.dumps_experimental("integrations.slack.enable-orjson", [blocks]),
         # Prevent duplicate unfurl
         # https://api.slack.com/reference/messaging/link-unfurling#no_unfurling_please
         "unfurl_links": False,

Some files were not shown because too many files changed in this diff