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

ref(slack): use sdk client to get channel id #72752

Merged
merged 11 commits into from
Jun 25, 2024

Conversation

iamrajjoshi
Copy link
Member

Adds feature-flagged usage of Slack SDK client to check channel id by schedule-sending a message and then immediately deleting. Also adds tests for the code area.

@iamrajjoshi iamrajjoshi requested a review from a team June 13, 2024 22:51
@iamrajjoshi iamrajjoshi self-assigned this Jun 13, 2024
@iamrajjoshi iamrajjoshi requested a review from a team as a code owner June 13, 2024 22:51
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Jun 13, 2024
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
@iamrajjoshi iamrajjoshi requested a review from a team as a code owner June 14, 2024 00:13
@iamrajjoshi
Copy link
Member Author

had to update some other tests because of the feature flag check 😢

src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
src/sentry/integrations/slack/utils/channel.py Outdated Show resolved Hide resolved
tests/sentry/integrations/slack/test_utils.py Show resolved Hide resolved
Copy link

codecov bot commented Jun 21, 2024

Codecov Report

Attention: Patch coverage is 71.13402% with 28 lines in your changes missing coverage. Please review.

Project coverage is 78.01%. Comparing base (9e46db8) to head (a31c45b).
Report is 9 commits behind head on master.

Current head a31c45b differs from pull request most recent head dff1f41

Please upload reports for the commit dff1f41 to get more accurate results.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #72752      +/-   ##
==========================================
- Coverage   78.03%   78.01%   -0.02%     
==========================================
  Files        6632     6632              
  Lines      296032   296094      +62     
  Branches    50994    51002       +8     
==========================================
- Hits       230994   230993       -1     
- Misses      58754    58814      +60     
- Partials     6284     6287       +3     
Files Coverage Δ
src/sentry/features/temporary.py 100.00% <100.00%> (ø)
src/sentry/incidents/logic.py 90.54% <100.00%> (ø)
src/sentry/integrations/slack/actions/form.py 93.05% <100.00%> (+0.19%) ⬆️
.../sentry/integrations/slack/actions/notification.py 91.42% <100.00%> (+0.06%) ⬆️
src/sentry/integrations/slack/utils/__init__.py 100.00% <100.00%> (ø)
src/sentry/integrations/slack/utils/users.py 76.81% <100.00%> (-15.95%) ⬇️
.../serializers/rest_framework/notification_action.py 76.64% <50.00%> (ø)
...sks/integrations/slack/find_channel_id_for_rule.py 68.75% <55.55%> (-0.11%) ⬇️
src/sentry/integrations/slack/utils/channel.py 77.27% <69.44%> (-7.35%) ⬇️

... and 14 files with indirect coverage changes

"types": "public_channel,private_channel",
}
try:
users_list = client.users_list(limit=SLACK_GET_CHANNEL_ID_PAGE_SIZE, kwargs=payload)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will replace this after cathy's refactor pr gets merged

@@ -1,6 +1,5 @@
__all__ = (
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am planning to add a task to clean these files at the end of the refactoring

SLACK_DEFAULT_TIMEOUT = 10
MEMBER_PREFIX = "@"
CHANNEL_PREFIX = "#"
strip_channel_chars = "".join([MEMBER_PREFIX, CHANNEL_PREFIX])


@dataclass
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be frozen?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can't be because i modify the instance in the function.

Comment on lines 199 to 200
if time.time() > time_to_quit:
break
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(i'm wondering what the timeout is for? i don't see this being kicked off as an async task. maybe some API calls have a timeout)

should we return SlackChannelIdData with timed_out=True for the timeout here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a timeout in case the member list is extremely long, in which case the function will return early if it can't find a user that matches in time. I should return early here as you said.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i guess i'm wondering what is necessitating the timeout in terms of the call stack, it's probably some upstream caller then

Comment on lines 154 to 157
: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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's no longer returning a tuple. If these field details need to be documented, we should move them to the dataclass definition.

id_data.prefix = "#"
except SlackApiError:
logger.exception("rule.slack.channel_check_error", extra=logger_params)
return id_data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should document the meaning of returning SlackChannelIdData(prefix="", channel_id=None, timed_out=False) in the name is None case. It adds a case where prefix is not "#" or "@" as promised in the docstring, for instance. Do we expect the caller to check for this? Would it be appropriate to return None instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have looked through callers, most of them complain loudly when the channel_id is None. its a good call to document this case.

Comment on lines 171 to 172
id_data.channel_id = check_for_channel(client, name)
id_data.prefix = "#"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's refactor this flow to make SlackChannelIdData immutable. We could use local variables here and only construct the object when we're ready to return.


# We need to check for individual users if we don't have a channel
users = get_users_sdk(client, integration)
for user in users:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This for-loop has enough going on (iterating over users and trying to find a match on a best-effort basis before timing out) that I think it's worth breaking out into a private helper method.

# 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 str(user["name"]).lower() == name.lower():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to call .casefold() than .lower() to avoid problems with obscure Unicode letters. https://stackoverflow.com/a/319435

}
logger.exception("slack.chat_scheduleMessage.error", extra=logger_params)
if "channel_not_found" in str(e):
return None
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an expected condition? Will it happen often enough that we don't want to call logger.exception every time?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Essentially this channel checks for either a channel or a particular user. if we get a channel not found, we attempt to find a user with the particular name, which is why we have to end up checking for this error

Comment on lines +169 to +170
_channel_id = None
_prefix = ""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wondering why you chose to have underscores here? these aren't global variables?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i did that cause intellisense kept suggesting the variables defined in the previous function were in scope here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weird

@iamrajjoshi iamrajjoshi enabled auto-merge (squash) June 25, 2024 20:23
@iamrajjoshi iamrajjoshi merged commit 933d3d0 into master Jun 25, 2024
48 checks passed
@iamrajjoshi iamrajjoshi deleted the raj/mes-ref/slack/sdk-2.10 branch June 25, 2024 20:26
Copy link

sentry-io bot commented Jun 26, 2024

Suspect Issues

This pull request was deployed and Sentry observed the following issues:

Did you find this useful? React with a 👍 or 👎

@github-actions github-actions bot locked and limited conversation to collaborators Jul 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants