Repository: getsentry/sentry

Issue:
Remove unused Slack channel lookup code
Since https://github.com/getsentry/sentry/pull/52034/files has been out with no issues for long enough, we can remove the feature flag and all the code it replaces.



Discussion:

Resolving patch:
diff --git a/src/sentry/conf/server.py b/src/sentry/conf/server.py
--- a/src/sentry/conf/server.py
+++ b/src/sentry/conf/server.py
@@ -1682,8 +1682,6 @@ def SOCIAL_AUTH_DEFAULT_USERNAME() -> str:
     "organizations:org-auth-tokens": False,
     # Enable detecting SDK crashes during event processing
     "organizations:sdk-crash-detection": False,
-    # Enables slack channel lookup via schedule message
-    "organizations:slack-use-new-lookup": False,
     # Enable functionality for recap server polling.
     "organizations:recap-server": False,
     # Adds additional filters and a new section to issue alert rules.
diff --git a/src/sentry/features/__init__.py b/src/sentry/features/__init__.py
--- a/src/sentry/features/__init__.py
+++ b/src/sentry/features/__init__.py
@@ -260,7 +260,6 @@
 default_manager.add("organizations:ds-sliding-window", OrganizationFeature, FeatureHandlerStrategy.INTERNAL)
 default_manager.add("organizations:ds-sliding-window-org", OrganizationFeature, FeatureHandlerStrategy.INTERNAL)
 default_manager.add("organizations:ds-org-recalibration", OrganizationFeature, FeatureHandlerStrategy.INTERNAL)
-default_manager.add("organizations:slack-use-new-lookup", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
 default_manager.add("organizations:slack-disable-on-broken", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
 default_manager.add("organizations:sourcemaps-bundle-flat-file-indexing", OrganizationFeature, FeatureHandlerStrategy.REMOTE)
 default_manager.add("organizations:recap-server", OrganizationFeature, FeatureHandlerStrategy.INTERNAL)
diff --git a/src/sentry/integrations/slack/utils/channel.py b/src/sentry/integrations/slack/utils/channel.py
--- a/src/sentry/integrations/slack/utils/channel.py
+++ b/src/sentry/integrations/slack/utils/channel.py
@@ -5,7 +5,6 @@
 
 from django.core.exceptions import ValidationError
 
-from sentry import features
 from sentry.integrations.slack.client import SlackClient
 from sentry.models import Integration, Organization
 from sentry.services.hybrid_cloud.integration import RpcIntegration
@@ -61,14 +60,12 @@ def get_channel_id(
     else:
         timeout = SLACK_DEFAULT_TIMEOUT
 
-    # XXX(meredith): For large accounts that have many, many channels it's
-    # possible for us to timeout while attempting to paginate through to find the channel id
+    # XXX(meredith): For large accounts that have many, many users it's
+    # possible for us to timeout while attempting to paginate through to find the user id
     # This means some users are unable to create/update alert rules. To avoid this, we attempt
     # to find the channel id asynchronously if it takes longer than a certain amount of time,
     # which I have set as the SLACK_DEFAULT_TIMEOUT - arbitrarily - to 10 seconds.
 
-    if features.has("organizations:slack-use-new-lookup", organization):
-        return get_channel_id_with_timeout_new(integration, channel_name, timeout)
     return get_channel_id_with_timeout(integration, channel_name, timeout)
 
 
@@ -106,89 +103,6 @@ def get_channel_id_with_timeout(
     integration: Integration | RpcIntegration,
     name: Optional[str],
     timeout: int,
-) -> Tuple[str, Optional[str], bool]:
-    """
-    Fetches the internal slack id of a channel.
-    :param integration: The slack integration
-    :param name: The name of the channel
-    :param timeout: Our self-imposed time limit.
-    :return: a tuple of three values
-        1. prefix: string (`"#"` or `"@"`)
-        2. channel_id: string or `None`
-        3. timed_out: boolean (whether we hit our self-imposed time limit)
-    """
-
-    payload = {
-        "exclude_archived": False,
-        "exclude_members": True,
-        "types": "public_channel,private_channel",
-    }
-
-    list_types = LIST_TYPES
-
-    time_to_quit = time.time() + timeout
-
-    client = SlackClient(integration_id=integration.id)
-    id_data: Optional[Tuple[str, Optional[str], bool]] = None
-    found_duplicate = False
-    prefix = ""
-    for list_type, result_name, prefix in list_types:
-        cursor = ""
-        while True:
-            endpoint = f"/{list_type}.list"
-            try:
-                # Slack limits the response of `<list_type>.list` to 1000 channels
-                items = client.get(endpoint, params=dict(payload, cursor=cursor, limit=1000))
-            except ApiRateLimitedError as e:
-                logger.info(
-                    f"rule.slack.{list_type}_list_rate_limited",
-                    extra={"error": str(e), "integration_id": integration.id},
-                )
-                raise e
-            except ApiError as e:
-                logger.info(
-                    f"rule.slack.{list_type}_list_other_error",
-                    extra={"error": str(e), "integration_id": integration.id},
-                )
-                return prefix, None, False
-
-            if not isinstance(items, dict):
-                continue
-
-            for c in items[result_name]:
-                # The "name" field is unique (this is the username for users)
-                # so we return immediately if we find a match.
-                # convert to lower case since all names in Slack are lowercase
-                if name and c["name"].lower() == name.lower():
-                    return prefix, c["id"], False
-                # If we don't get a match on a unique identifier, we look through
-                # the users' display names, and error if there is a repeat.
-                if list_type == "users":
-                    profile = c.get("profile")
-                    if profile and profile.get("display_name") == name:
-                        if id_data:
-                            found_duplicate = True
-                        else:
-                            id_data = (prefix, c["id"], False)
-
-            cursor = items.get("response_metadata", {}).get("next_cursor", None)
-            if time.time() > time_to_quit:
-                return prefix, None, True
-
-            if not cursor:
-                break
-        if found_duplicate:
-            raise DuplicateDisplayNameError(name)
-        elif id_data:
-            return id_data
-
-    return prefix, None, False
-
-
-def get_channel_id_with_timeout_new(
-    integration: Integration | RpcIntegration,
-    name: Optional[str],
-    timeout: int,
 ) -> Tuple[str, Optional[str], bool]:
     """
     Fetches the internal slack id of a channel using scheduled message.


Test patch:
diff --git a/tests/sentry/api/endpoints/notifications/test_notification_actions_details.py b/tests/sentry/api/endpoints/notifications/test_notification_actions_details.py
--- a/tests/sentry/api/endpoints/notifications/test_notification_actions_details.py
+++ b/tests/sentry/api/endpoints/notifications/test_notification_actions_details.py
@@ -18,6 +18,7 @@
 from sentry.testutils.cases import APITestCase
 from sentry.testutils.helpers.slack import install_slack
 from sentry.testutils.silo import assume_test_silo_mode, region_silo_test
+from sentry.utils import json
 
 
 @region_silo_test(stable=True)
@@ -233,26 +234,23 @@ class MockActionRegistration(ActionRegistration):
 
         self.mock_register(data)(MockActionRegistration)
 
-        # Can't find slack channel
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
-            status=500,
-        )
-        self.get_error_response(
-            self.organization.slug,
-            self.notif_action.id,
-            status_code=status.HTTP_400_BAD_REQUEST,
-            method="PUT",
-            **data,
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps(
+                {"ok": "true", "channel": channel_id, "scheduled_message_id": "Q1298393284"}
+            ),
         )
-        # Successful search for channel
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
             status=200,
-            json={"ok": True, "channels": [{"name": channel_name, "id": channel_id}]},
+            content_type="application/json",
+            body=json.dumps({"ok": True}),
         )
+
         response = self.get_success_response(
             self.organization.slug,
             self.notif_action.id,
diff --git a/tests/sentry/api/endpoints/notifications/test_notification_actions_index.py b/tests/sentry/api/endpoints/notifications/test_notification_actions_index.py
--- a/tests/sentry/api/endpoints/notifications/test_notification_actions_index.py
+++ b/tests/sentry/api/endpoints/notifications/test_notification_actions_index.py
@@ -18,6 +18,7 @@
 from sentry.testutils.cases import APITestCase
 from sentry.testutils.helpers.slack import install_slack
 from sentry.testutils.silo import assume_test_silo_mode, region_silo_test
+from sentry.utils import json
 
 
 @region_silo_test(stable=True)
@@ -281,24 +282,21 @@ class MockActionRegistration(ActionRegistration):
 
         self.mock_register(data)(MockActionRegistration)
 
-        # Can't find slack channel
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
-            status=500,
-        )
-        self.get_error_response(
-            self.organization.slug,
-            status_code=status.HTTP_400_BAD_REQUEST,
-            method="POST",
-            **data,
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps(
+                {"ok": "true", "channel": channel_id, "scheduled_message_id": "Q1298393284"}
+            ),
         )
-        # Successful search for channel
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
             status=200,
-            json={"ok": True, "channels": [{"name": channel_name, "id": channel_id}]},
+            content_type="application/json",
+            body=json.dumps({"ok": True}),
         )
         response = self.get_success_response(
             self.organization.slug,
diff --git a/tests/sentry/incidents/action_handlers/test_slack.py b/tests/sentry/incidents/action_handlers/test_slack.py
--- a/tests/sentry/incidents/action_handlers/test_slack.py
+++ b/tests/sentry/incidents/action_handlers/test_slack.py
@@ -28,14 +28,21 @@ def setUp(self):
         self.channel_id = "some_id"
         self.channel_name = "#hello"
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
             body=json.dumps(
-                {"ok": "true", "channels": [{"name": self.channel_name[1:], "id": self.channel_id}]}
+                {"ok": "true", "channel": self.channel_id, "scheduled_message_id": "Q1298393284"}
             ),
         )
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps({"ok": True}),
+        )
         self.action = self.create_alert_rule_trigger_action(
             target_identifier=self.channel_name,
             type=AlertRuleTriggerAction.Type.SLACK,
diff --git a/tests/sentry/incidents/endpoints/test_serializers.py b/tests/sentry/incidents/endpoints/test_serializers.py
--- a/tests/sentry/incidents/endpoints/test_serializers.py
+++ b/tests/sentry/incidents/endpoints/test_serializers.py
@@ -30,6 +30,7 @@
 from sentry.services.hybrid_cloud.app import app_service
 from sentry.services.hybrid_cloud.integration import integration_service
 from sentry.services.hybrid_cloud.integration.serial import serialize_integration
+from sentry.shared_integrations.exceptions import ApiError
 from sentry.silo import SiloMode
 from sentry.snuba.dataset import Dataset
 from sentry.snuba.models import SnubaQuery, SnubaQueryEventType
@@ -41,7 +42,18 @@
 
 
 @region_silo_test(stable=True)
-class TestAlertRuleSerializer(TestCase):
+class TestAlertRuleSerializerBase(TestCase):
+    @assume_test_silo_mode(SiloMode.CONTROL)
+    def setUp(self):
+        self.integration = Integration.objects.create(
+            external_id="1",
+            provider="slack",
+            metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
+        )
+        self.integration.add_organization(self.organization, self.user)
+
+
+class TestAlertRuleSerializer(TestAlertRuleSerializerBase):
     @cached_property
     def valid_params(self):
         return {
@@ -107,15 +119,6 @@ def run_fail_validation_test(self, params, errors):
         assert not serializer.is_valid()
         assert serializer.errors == errors
 
-    @assume_test_silo_mode(SiloMode.CONTROL)
-    def setup_slack_integration(self):
-        self.integration = Integration.objects.create(
-            external_id="1",
-            provider="slack",
-            metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
-        )
-        self.integration.add_organization(self.organization, self.user)
-
     def test_validation_no_params(self):
         serializer = AlertRuleSerializer(context=self.context, data={})
         assert not serializer.is_valid()
@@ -454,13 +457,6 @@ def test_invalid_slack_channel(self):
         # and that the rule is not created.
         base_params = self.valid_params.copy()
         base_params["name"] = "Aun1qu3n4m3"
-        with assume_test_silo_mode(SiloMode.CONTROL):
-            integration = Integration.objects.create(
-                external_id="1",
-                provider="slack",
-                metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
-            )
-            integration.add_organization(self.organization, self.user)
         base_params["triggers"][0]["actions"].append(
             {
                 "type": AlertRuleTriggerAction.get_registered_type(
@@ -470,12 +466,12 @@ def test_invalid_slack_channel(self):
                     AlertRuleTriggerAction.TargetType.SPECIFIC
                 ],
                 "targetIdentifier": "123",
-                "integration": str(integration.id),
+                "integration": str(self.integration.id),
             }
         )
         serializer = AlertRuleSerializer(context=self.context, data=base_params)
         assert serializer.is_valid()
-        with pytest.raises(serializers.ValidationError):
+        with pytest.raises(ApiError):
             serializer.save()
 
         # Make sure the rule was not created.
@@ -483,7 +479,7 @@ def test_invalid_slack_channel(self):
 
         # Make sure the action was not created.
         alert_rule_trigger_actions = list(
-            AlertRuleTriggerAction.objects.filter(integration_id=integration.id)
+            AlertRuleTriggerAction.objects.filter(integration_id=self.integration.id)
         )
         assert len(alert_rule_trigger_actions) == 0
 
@@ -528,7 +524,6 @@ def test_threshold_type(self):
         return_value=("#", None, True),
     )
     def test_channel_timeout(self, mock_get_channel_id):
-        self.setup_slack_integration()
         trigger = {
             "label": "critical",
             "alertThreshold": 200,
@@ -558,7 +553,6 @@ def test_channel_timeout(self, mock_get_channel_id):
         return_value=("#", None, True),
     )
     def test_invalid_team_with_channel_timeout(self, mock_get_channel_id):
-        self.setup_slack_integration()
         other_org = self.create_organization()
         new_team = self.create_team(organization=other_org)
         trigger = {
@@ -726,7 +720,7 @@ def test_enforce_max_subscriptions(self):
         assert excinfo.value.detail[0] == "You may not exceed 1 metric alerts per organization"
 
 
-class TestAlertRuleTriggerSerializer(TestCase):
+class TestAlertRuleTriggerSerializer(TestAlertRuleSerializerBase):
     @cached_property
     def other_project(self):
         return self.create_project()
@@ -775,7 +769,7 @@ def test_validation_no_params(self):
         }
 
 
-class TestAlertRuleTriggerActionSerializer(TestCase):
+class TestAlertRuleTriggerActionSerializer(TestAlertRuleSerializerBase):
     @cached_property
     def other_project(self):
         return self.create_project()
@@ -902,12 +896,6 @@ def test_slack(self):
             },
             {"integration": ["Integration must be provided for slack"]},
         )
-        integration = Integration.objects.create(
-            external_id="1",
-            provider="slack",
-            metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
-        )
-        integration.add_organization(self.organization, self.user)
 
         base_params = self.valid_params.copy()
         base_params.update(
@@ -919,12 +907,12 @@ def test_slack(self):
                     AlertRuleTriggerAction.TargetType.SPECIFIC
                 ],
                 "targetIdentifier": "123",
-                "integration": str(integration.id),
+                "integration": str(self.integration.id),
             }
         )
         serializer = AlertRuleTriggerActionSerializer(context=self.context, data=base_params)
         assert serializer.is_valid()
-        with pytest.raises(serializers.ValidationError):
+        with pytest.raises(ApiError):
             serializer.save()
 
     @responses.activate
@@ -932,13 +920,6 @@ def test_valid_slack_channel_id(self):
         """
         Test that when a valid Slack channel ID is provided, we look up the channel name and validate it against the targetIdentifier.
         """
-        integration = Integration.objects.create(
-            external_id="1",
-            provider="slack",
-            metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
-        )
-        integration.add_organization(self.organization, self.user)
-
         base_params = self.valid_params.copy()
         base_params.update(
             {
@@ -949,7 +930,7 @@ def test_valid_slack_channel_id(self):
                     AlertRuleTriggerAction.TargetType.SPECIFIC
                 ],
                 "targetIdentifier": "merp",
-                "integration": str(integration.id),
+                "integration": str(self.integration.id),
             }
         )
         context = self.context.copy()
@@ -968,7 +949,7 @@ def test_valid_slack_channel_id(self):
 
         # # Make sure the action was created.
         alert_rule_trigger_actions = list(
-            AlertRuleTriggerAction.objects.filter(integration_id=integration.id)
+            AlertRuleTriggerAction.objects.filter(integration_id=self.integration.id)
         )
         assert len(alert_rule_trigger_actions) == 1
 
@@ -977,13 +958,6 @@ def test_invalid_slack_channel_id(self):
         """
         Test that an invalid Slack channel ID is detected and blocks the action from being saved.
         """
-        integration = Integration.objects.create(
-            external_id="1",
-            provider="slack",
-            metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
-        )
-        integration.add_organization(self.organization, self.user)
-
         base_params = self.valid_params.copy()
         base_params.update(
             {
@@ -994,7 +968,7 @@ def test_invalid_slack_channel_id(self):
                     AlertRuleTriggerAction.TargetType.SPECIFIC
                 ],
                 "targetIdentifier": "merp",
-                "integration": str(integration.id),
+                "integration": str(self.integration.id),
             }
         )
         context = self.context.copy()
@@ -1011,7 +985,7 @@ def test_invalid_slack_channel_id(self):
 
         # # Make sure the action was not created.
         alert_rule_trigger_actions = list(
-            AlertRuleTriggerAction.objects.filter(integration_id=integration.id)
+            AlertRuleTriggerAction.objects.filter(integration_id=self.integration.id)
         )
         assert len(alert_rule_trigger_actions) == 0
 
@@ -1020,13 +994,6 @@ def test_invalid_slack_channel_name(self):
         """
         Test that an invalid Slack channel name is detected and blocks the action from being saved.
         """
-        integration = Integration.objects.create(
-            external_id="1",
-            provider="slack",
-            metadata={"access_token": "xoxp-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"},
-        )
-        integration.add_organization(self.organization, self.user)
-
         base_params = self.valid_params.copy()
         base_params.update(
             {
@@ -1037,7 +1004,7 @@ def test_invalid_slack_channel_name(self):
                     AlertRuleTriggerAction.TargetType.SPECIFIC
                 ],
                 "targetIdentifier": "123",
-                "integration": str(integration.id),
+                "integration": str(self.integration.id),
             }
         )
         context = self.context.copy()
@@ -1054,7 +1021,7 @@ def test_invalid_slack_channel_name(self):
 
         # # Make sure the action was not created.
         alert_rule_trigger_actions = list(
-            AlertRuleTriggerAction.objects.filter(integration_id=integration.id)
+            AlertRuleTriggerAction.objects.filter(integration_id=self.integration.id)
         )
         assert len(alert_rule_trigger_actions) == 0
 
diff --git a/tests/sentry/incidents/test_logic.py b/tests/sentry/incidents/test_logic.py
--- a/tests/sentry/incidents/test_logic.py
+++ b/tests/sentry/incidents/test_logic.py
@@ -68,7 +68,7 @@
 )
 from sentry.models import ActorTuple, Integration, OrganizationIntegration, PagerDutyService
 from sentry.models.actor import get_actor_id_for_user
-from sentry.shared_integrations.exceptions import ApiRateLimitedError
+from sentry.shared_integrations.exceptions import ApiError, ApiRateLimitedError
 from sentry.snuba.dataset import Dataset
 from sentry.snuba.models import QuerySubscription, SnubaQuery, SnubaQueryEventType
 from sentry.testutils.cases import BaseIncidentsTest, BaseMetricsTestCase, SnubaTestCase, TestCase
@@ -1235,14 +1235,21 @@ def test_slack(self):
         channel_name = "#some_channel"
         channel_id = "s_c"
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
             body=json.dumps(
-                {"ok": "true", "channels": [{"name": channel_name[1:], "id": channel_id}]}
+                {"ok": "true", "channel": channel_id, "scheduled_message_id": "Q1298393284"}
             ),
         )
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps({"ok": True}),
+        )
 
         action = create_alert_rule_trigger_action(
             self.trigger,
@@ -1268,7 +1275,7 @@ def test_slack_not_existing(self):
         type = AlertRuleTriggerAction.Type.SLACK
         target_type = AlertRuleTriggerAction.TargetType.SPECIFIC
         channel_name = "#some_channel_that_doesnt_exist"
-        with pytest.raises(InvalidTriggerActionError):
+        with pytest.raises(ApiError):
             create_alert_rule_trigger_action(
                 self.trigger,
                 type,
@@ -1293,12 +1300,20 @@ def test_slack_rate_limiting(self):
         target_type = AlertRuleTriggerAction.TargetType.SPECIFIC
         channel_name = "#some_channel"
 
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps({"ok": False, "error": "channel_not_found"}),
+        )
+
         responses.add(
             method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            url="https://slack.com/api/users.list",
             status=429,
             content_type="application/json",
-            body=json.dumps({"ok": "false", "error": "ratelimited"}),
+            body=json.dumps({"ok": False, "error": "ratelimited"}),
         )
         with pytest.raises(ApiRateLimitedError):
             create_alert_rule_trigger_action(
@@ -1451,14 +1466,21 @@ def test_slack(self):
         channel_name = "#some_channel"
         channel_id = "s_c"
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
             body=json.dumps(
-                {"ok": "true", "channels": [{"name": channel_name[1:], "id": channel_id}]}
+                {"ok": "true", "channel": channel_id, "scheduled_message_id": "Q1298393284"}
             ),
         )
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps({"ok": True}),
+        )
 
         action = update_alert_rule_trigger_action(
             self.action,
@@ -1484,7 +1506,7 @@ def test_slack_not_existing(self):
         type = AlertRuleTriggerAction.Type.SLACK
         target_type = AlertRuleTriggerAction.TargetType.SPECIFIC
         channel_name = "#some_channel_that_doesnt_exist"
-        with pytest.raises(InvalidTriggerActionError):
+        with pytest.raises(ApiError):
             update_alert_rule_trigger_action(
                 self.action,
                 type,
@@ -1509,12 +1531,20 @@ def test_slack_rate_limiting(self):
         target_type = AlertRuleTriggerAction.TargetType.SPECIFIC
         channel_name = "#some_channel"
 
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps({"ok": False, "error": "channel_not_found"}),
+        )
+
         responses.add(
             method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            url="https://slack.com/api/users.list",
             status=429,
             content_type="application/json",
-            body=json.dumps({"ok": "false", "error": "ratelimited"}),
+            body=json.dumps({"ok": False, "error": "ratelimited"}),
         )
         with pytest.raises(ApiRateLimitedError):
             update_alert_rule_trigger_action(
diff --git a/tests/sentry/integrations/slack/test_notify_action.py b/tests/sentry/integrations/slack/test_notify_action.py
--- a/tests/sentry/integrations/slack/test_notify_action.py
+++ b/tests/sentry/integrations/slack/test_notify_action.py
@@ -109,20 +109,21 @@ def test_valid_bot_channel_selected(self):
             data={"workspace": integration.id, "channel": "#my-channel", "tags": ""}
         )
 
-        channels = {
-            "ok": "true",
-            "channels": [
-                {"name": "my-channel", "id": "chan-id"},
-                {"name": "other-chann", "id": "chan-id"},
-            ],
-        }
-
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
-            body=json.dumps(channels),
+            body=json.dumps(
+                {"ok": "true", "channel": "chan-id", "scheduled_message_id": "Q1298393284"}
+            ),
+        )
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps({"ok": True}),
         )
 
         form = rule.get_form_instance()
@@ -135,20 +136,12 @@ def test_valid_member_selected(self):
             data={"workspace": self.integration.id, "channel": "@morty", "tags": ""}
         )
 
-        channels = {
-            "ok": "true",
-            "channels": [
-                {"name": "my-channel", "id": "chan-id"},
-                {"name": "other-chann", "id": "chan-id"},
-            ],
-        }
-
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
-            body=json.dumps(channels),
+            body=json.dumps({"ok": False, "error": "channel_not_found"}),
         )
 
         members = {
@@ -176,14 +169,12 @@ def test_invalid_channel_selected(self):
             data={"workspace": self.integration.id, "channel": "#my-channel", "tags": ""}
         )
 
-        channels = {"ok": "true", "channels": [{"name": "other-chann", "id": "chan-id"}]}
-
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
-            body=json.dumps(channels),
+            body=json.dumps({"ok": False, "error": "channel_not_found"}),
         )
 
         members = {"ok": "true", "members": [{"name": "other-member", "id": "member-id"}]}
@@ -205,25 +196,20 @@ def test_invalid_channel_selected(self):
     def test_rate_limited_response(self):
         """Should surface a 429 from Slack to the frontend form"""
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.info",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
-            body=json.dumps({"ok": "true", "channel": {"name": "my-channel", "id": "C2349874"}}),
+            body=json.dumps({"ok": False, "error": "channel_not_found"}),
         )
+
         responses.add(
             method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            url="https://slack.com/api/users.list",
             status=429,
             content_type="application/json",
-            body=json.dumps(
-                {
-                    "ok": "false",
-                    "error": "ratelimited",
-                }
-            ),
+            body=json.dumps({"ok": False, "error": "ratelimited"}),
         )
-
         rule = self.get_rule(
             data={
                 "workspace": self.integration.id,
@@ -321,11 +307,11 @@ def test_display_name_conflict(self):
         )
 
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
             status=200,
             content_type="application/json",
-            body=json.dumps({"ok": "true", "channels": []}),
+            body=json.dumps({"ok": False, "error": "channel_not_found"}),
         )
 
         members = {
diff --git a/tests/sentry/integrations/slack/test_tasks.py b/tests/sentry/integrations/slack/test_tasks.py
--- a/tests/sentry/integrations/slack/test_tasks.py
+++ b/tests/sentry/integrations/slack/test_tasks.py
@@ -6,7 +6,7 @@
 import responses
 
 from sentry.incidents.models import AlertRule, AlertRuleTriggerAction
-from sentry.integrations.slack.utils import SLACK_RATE_LIMITED_MESSAGE, RedisRuleStatus
+from sentry.integrations.slack.utils import RedisRuleStatus
 from sentry.models import Rule
 from sentry.receivers.rules import DEFAULT_RULE_LABEL
 from sentry.services.hybrid_cloud.integration.serial import serialize_integration
@@ -26,15 +26,21 @@ class SlackTasksTest(TestCase):
     def setUp(self):
         self.integration = install_slack(self.organization)
         self.uuid = uuid4().hex
-
-        channels = {"ok": "true", "channels": [{"name": "my-channel", "id": "chan-id"}]}
-
         responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/conversations.list",
+            method=responses.POST,
+            url="https://slack.com/api/chat.scheduleMessage",
+            status=200,
+            content_type="application/json",
+            body=json.dumps(
+                {"ok": "true", "channel": "chan-id", "scheduled_message_id": "Q1298393284"}
+            ),
+        )
+        responses.add(
+            method=responses.POST,
+            url="https://slack.com/api/chat.deleteScheduledMessage",
             status=200,
             content_type="application/json",
-            body=json.dumps(channels),
+            body=json.dumps({"ok": True}),
         )
 
     @cached_property
@@ -158,80 +164,6 @@ def test_task_existing_rule(self, mock_set_value):
             }
         ]
 
-    @responses.activate
-    @patch.object(RedisRuleStatus, "set_value", return_value=None)
-    def test_task_failed_channel_id_lookup(self, mock_set_value):
-        members = {"ok": "true", "members": [{"name": "morty", "id": "morty-id"}]}
-        responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/users.list",
-            status=200,
-            content_type="application/json",
-            body=json.dumps(members),
-        )
-
-        data = {
-            "name": "Test Rule",
-            "environment": None,
-            "project": self.project,
-            "action_match": "all",
-            "filter_match": "all",
-            "conditions": [{"id": "sentry.rules.conditions.every_event.EveryEventCondition"}],
-            "actions": [
-                {
-                    "channel": "#some-channel",
-                    "id": "sentry.integrations.slack.notify_action.SlackNotifyServiceAction",
-                    "name": "Send a notification to the funinthesun Slack workspace to #secrets and show tags [] in notification",
-                    "tags": "",
-                    "workspace": self.integration.id,
-                }
-            ],
-            "frequency": 5,
-            "uuid": self.uuid,
-        }
-
-        with self.tasks():
-            find_channel_id_for_rule(**data)
-
-        mock_set_value.assert_called_with("failed")
-
-    @responses.activate
-    @patch.object(RedisRuleStatus, "set_value", return_value=None)
-    def test_task_rate_limited_channel_id_lookup(self, mock_set_value):
-        """Should set the correct error value when rate limited"""
-        responses.add(
-            method=responses.GET,
-            url="https://slack.com/api/users.list",
-            status=429,
-            content_type="application/json",
-            body=json.dumps({"ok": "true", "error": "ratelimited"}),
-        )
-
-        data = {
-            "name": "Test Rule",
-            "environment": None,
-            "project": self.project,
-            "action_match": "all",
-            "filter_match": "all",
-            "conditions": [{"id": "sentry.rules.conditions.every_event.EveryEventCondition"}],
-            "actions": [
-                {
-                    "channel": "@user",
-                    "id": "sentry.integrations.slack.notify_action.SlackNotifyServiceAction",
-                    "name": "Send a notification to the funinthesun Slack workspace to #secrets and show tags [] in notification",
-                    "tags": "",
-                    "workspace": self.integration.id,
-                }
-            ],
-            "frequency": 5,
-            "uuid": self.uuid,
-        }
-
-        with self.tasks():
-            find_channel_id_for_rule(**data)
-
-        mock_set_value.assert_called_with("failed", None, SLACK_RATE_LIMITED_MESSAGE)
-
     @patch.object(RedisRuleStatus, "set_value", return_value=None)
     @patch(
         "sentry.integrations.slack.utils.channel.get_channel_id_with_timeout",
diff --git a/tests/sentry/integrations/slack/test_utils.py b/tests/sentry/integrations/slack/test_utils.py
--- a/tests/sentry/integrations/slack/test_utils.py
+++ b/tests/sentry/integrations/slack/test_utils.py
@@ -3,125 +3,33 @@
 
 from sentry.integrations.slack.utils import get_channel_id
 from sentry.integrations.slack.utils.channel import CHANNEL_PREFIX, MEMBER_PREFIX
-from sentry.models import Integration
 from sentry.shared_integrations.exceptions import ApiRateLimitedError, DuplicateDisplayNameError
 from sentry.testutils.cases import TestCase
-from sentry.testutils.helpers import install_slack, with_feature
+from sentry.testutils.helpers import install_slack
 from sentry.utils import json
 
 
 class GetChannelIdTest(TestCase):
-    def add_list_response(self, list_type, channels, result_name="channels"):
-        self.resp = responses.mock
-        self.resp.add(
-            method=responses.GET,
-            url="https://slack.com/api/%s.list" % list_type,
-            status=200,
-            content_type="application/json",
-            body=json.dumps({"ok": "true", result_name: channels}),
-        )
-
-
-class GetChannelIdBotTest(GetChannelIdTest):
     def setUp(self):
-
         self.resp = responses.mock
         self.resp.__enter__()
 
         self.integration = install_slack(self.event.project.organization)
 
-        self.add_list_response(
-            "conversations",
-            [
-                {"name": "my-channel", "id": "m-c"},
-                {"name": "other-chann", "id": "o-c"},
-                {"name": "my-private-channel", "id": "m-p-c", "is_private": True},
-            ],
-            result_name="channels",
-        )
-        self.add_list_response(
-            "users",
-            [
-                {"name": "first-morty", "id": "m", "profile": {"display_name": "Morty"}},
-                {"name": "other-user", "id": "o-u", "profile": {"display_name": "Jimbob"}},
-                {"name": "better_morty", "id": "bm", "profile": {"display_name": "Morty"}},
-            ],
-            result_name="members",
-        )
-
     def tearDown(self):
         self.resp.__exit__(None, None, None)
 
-    def run_valid_test(self, channel, expected_prefix, expected_id, timed_out):
-        assert (expected_prefix, expected_id, timed_out) == get_channel_id(
-            self.organization, self.integration, channel
-        )
-
-    def test_valid_channel_selected(self):
-        self.run_valid_test("#My-Channel", CHANNEL_PREFIX, "m-c", False)
-
-    def test_valid_private_channel_selected(self):
-        self.run_valid_test("#my-private-channel", CHANNEL_PREFIX, "m-p-c", False)
-
-    def test_valid_member_selected(self):
-        self.run_valid_test("@first-morty", MEMBER_PREFIX, "m", False)
-
-    def test_valid_member_selected_display_name(self):
-        self.run_valid_test("@Jimbob", MEMBER_PREFIX, "o-u", False)
-
-    def test_invalid_member_selected_display_name(self):
-        with pytest.raises(DuplicateDisplayNameError):
-            get_channel_id(self.organization, self.integration, "@Morty")
-
-    def test_invalid_channel_selected(self):
-        assert get_channel_id(self.organization, self.integration, "#fake-channel")[1] is None
-        assert get_channel_id(self.organization, self.integration, "@fake-user")[1] is None
-
-
-class GetChannelIdErrorBotTest(GetChannelIdTest):
-    def setUp(self):
+    def add_list_response(self, list_type, channels, result_name="channels"):
         self.resp = responses.mock
-        self.resp.__enter__()
-
-        self.integration = Integration.objects.create(
-            provider="slack",
-            name="Awesome Team",
-            external_id="TXXXXXXX1",
-            metadata={
-                "access_token": "xoxb-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx",
-                "installation_type": "born_as_bot",
-            },
-        )
-        self.integration.add_organization(self.event.project.organization, self.user)
-
-    def tearDown(self):
-        self.resp.__exit__(None, None, None)
-
-    def test_rate_limiting(self):
-        """Should handle 429 from Slack when searching for channels"""
         self.resp.add(
             method=responses.GET,
-            url="https://slack.com/api/conversations.list",
-            status=429,
+            url="https://slack.com/api/%s.list" % list_type,
+            status=200,
             content_type="application/json",
-            body=json.dumps({"ok": "false", "error": "ratelimited"}),
+            body=json.dumps({"ok": "true", result_name: channels}),
         )
-        with pytest.raises(ApiRateLimitedError):
-            get_channel_id(self.organization, self.integration, "@user")
-
-
-class GetChannelIdFasterTest(GetChannelIdTest):
-    def setUp(self):
-        self.resp = responses.mock
-        self.resp.__enter__()
-
-        self.integration = install_slack(self.event.project.organization)
-
-    def tearDown(self):
-        self.resp.__exit__(None, None, None)
 
     def add_msg_response(self, channel_id, result_name="channel"):
-
         if channel_id == "channel_not_found":
             bodydict = {"ok": False, "error": "channel_not_found"}
         else:
@@ -135,13 +43,12 @@ def add_msg_response(self, channel_id, result_name="channel"):
             body=json.dumps(bodydict),
         )
 
-    @with_feature("organizations:slack-use-new-lookup")
     def run_valid_test(self, channel, expected_prefix, expected_id, timed_out):
         assert (expected_prefix, expected_id, timed_out) == get_channel_id(
             self.organization, self.integration, channel
         )
 
-    def test_valid_channel_selected_new(self):
+    def test_valid_channel_selected(self):
         self.add_msg_response("m-c")
         self.resp.add(
             method=responses.POST,
@@ -152,7 +59,7 @@ def test_valid_channel_selected_new(self):
         )
         self.run_valid_test("#My-Channel", CHANNEL_PREFIX, "m-c", False)
 
-    def test_valid_private_channel_selected_new(self):
+    def test_valid_private_channel_selected(self):
         self.add_msg_response("m-p-c")
         self.resp.add(
             method=responses.POST,
@@ -189,7 +96,6 @@ def test_valid_member_selected_display_name(self):
         )
         self.run_valid_test("@Jimbob", MEMBER_PREFIX, "o-u", False)
 
-    @with_feature("organizations:slack-use-new-lookup")
     def test_invalid_member_selected_display_name(self):
         self.add_msg_response("channel_not_found")
         self.add_list_response(
@@ -204,15 +110,13 @@ def test_invalid_member_selected_display_name(self):
         with pytest.raises(DuplicateDisplayNameError):
             get_channel_id(self.organization, self.integration, "@Morty")
 
-    @with_feature("organizations:slack-use-new-lookup")
     def test_invalid_channel_selected(self):
         self.add_msg_response("channel_not_found")
         assert get_channel_id(self.organization, self.integration, "#fake-channel")[1] is None
         assert get_channel_id(self.organization, self.integration, "@fake-user")[1] is None
 
-    @with_feature("organizations:slack-use-new-lookup")
     def test_rate_limiting(self):
-        """Should handle 429 from Slack when searching for channels"""
+        """Should handle 429 from Slack when searching for users"""
         self.add_msg_response("channel_not_found")
         self.resp.add(
             method=responses.GET,