Skip to content

Commit

Permalink
ignoring client for Slack calls to make subsequent calls more efficient
Browse files Browse the repository at this point in the history
  • Loading branch information
whitdog47 committed Nov 13, 2024
1 parent 599b731 commit bb98d48
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 11 deletions.
3 changes: 2 additions & 1 deletion src/dispatch/incident/scheduled.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ def incident_report_weekly(db_session: Session, project: Project):
@timer
@scheduled_project_task
def incident_sync_members(db_session: Session, project: Project):
"""Checks the members of all conversations and ensures they are in the incident."""
"""Checks the members of all conversations associated with active
and stable incidents and ensures they are in the incident."""
plugin = plugin_service.get_active_instance(
db_session=db_session,
project_id=project.id,
Expand Down
3 changes: 2 additions & 1 deletion src/dispatch/plugins/dispatch_slack/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
does_user_exist,
emails_to_user_ids,
get_user_avatar_url,
get_user_info_by_id,
get_user_profile_by_email,
is_user,
rename_conversation,
Expand Down Expand Up @@ -467,7 +468,7 @@ def get_all_member_emails(self, conversation_id: str) -> list[str]:
member_emails = []
for member_id in member_ids:
if is_user(config=self.configuration, user_id=member_id):
user = client.users_info(user=member_id).get("user")
user = get_user_info_by_id(client, member_id)
if user:
member_emails.append(user["profile"]["email"])

Expand Down
68 changes: 59 additions & 9 deletions src/dispatch/plugins/dispatch_slack/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@
log = logging.getLogger(__name__)


class WebClientWrapper:
"""A wrapper for WebClient to make all instances with same token equal for caching."""

def __init__(self, client):
self._client = client

@property
def client(self):
return self._client

def __eq__(self, other):
return other._client.token == self._client.token

def __hash__(self):
return hash(type(self._client.token))


def create_slack_client(config: SlackConversationConfiguration) -> WebClient:
"""Creates a Slack Web API client."""
return WebClient(token=config.api_bot_token.get_secret_value())
Expand Down Expand Up @@ -179,28 +196,44 @@ def list_conversation_messages(client: WebClient, conversation_id: str, **kwargs


@functools.lru_cache()
def _get_domain(wrapper: WebClientWrapper) -> str:
"""Gets the team's Slack domain."""
return make_call(wrapper.client, SlackAPIGetEndpoints.team_info)["team"]["domain"]


def get_domain(client: WebClient) -> str:
"""Gets the team's Slack domain."""
return make_call(client, SlackAPIGetEndpoints.team_info)["team"]["domain"]
return _get_domain(WebClientWrapper(client))


@functools.lru_cache()
def _get_user_info_by_id(wrapper: WebClientWrapper, user_id: str) -> dict:
return make_call(wrapper.client, SlackAPIGetEndpoints.users_info, user=user_id)["user"]


def get_user_info_by_id(client: WebClient, user_id: str) -> dict:
"""Gets profile information about a user by id."""
return make_call(client, SlackAPIGetEndpoints.users_info, user=user_id)["user"]
return _get_user_info_by_id(WebClientWrapper(client), user_id)


@functools.lru_cache()
def _get_user_info_by_email(wrapper: WebClientWrapper, email: str) -> dict:
"""Gets profile information about a user by email."""
return make_call(wrapper.client, SlackAPIGetEndpoints.users_lookup_by_email, email=email)[
"user"
]


def get_user_info_by_email(client: WebClient, email: str) -> dict:
"""Gets profile information about a user by email."""
return make_call(client, SlackAPIGetEndpoints.users_lookup_by_email, email=email)["user"]
return _get_user_info_by_email(WebClientWrapper(client), email)


@functools.lru_cache()
def does_user_exist(client: WebClient, email: str) -> bool:
def _does_user_exist(wrapper: WebClientWrapper, email: str) -> bool:
"""Checks if a user exists in the Slack workspace by their email."""
try:
get_user_info_by_email(client, email)
get_user_info_by_email(wrapper.client, email)
return True
except SlackApiError as e:
if e.response["error"] == SlackAPIErrorCode.USERS_NOT_FOUND:
Expand All @@ -209,21 +242,38 @@ def does_user_exist(client: WebClient, email: str) -> bool:
raise


def does_user_exist(client: WebClient, email: str) -> bool:
"""Checks if a user exists in the Slack workspace by their email."""
return _does_user_exist(WebClientWrapper(client), email)


@functools.lru_cache()
def _get_user_profile_by_id(wrapper: WebClientWrapper, user_id: str) -> dict:
"""Gets profile information about a user by id."""
return make_call(wrapper.client, SlackAPIGetEndpoints.users_profile_get, user_id=user_id)[
"profile"
]


def get_user_profile_by_id(client: WebClient, user_id: str) -> dict:
"""Gets profile information about a user by id."""
return make_call(client, SlackAPIGetEndpoints.users_profile_get, user_id=user_id)["profile"]
return _get_user_profile_by_id(WebClientWrapper(client), user_id)


@functools.lru_cache()
def get_user_profile_by_email(client: WebClient, email: str) -> SlackResponse:
def _get_user_profile_by_email(wrapper: WebClientWrapper, email: str) -> SlackResponse:
"""Gets extended profile information about a user by email."""
user = get_user_info_by_email(client, email)
profile = get_user_profile_by_id(client, user["id"])
user = get_user_info_by_email(wrapper.client, email)
profile = get_user_profile_by_id(wrapper.client, user["id"])
profile["tz"] = user["tz"]
return profile


def get_user_profile_by_email(client: WebClient, email: str) -> SlackResponse:
"""Gets extended profile information about a user by email."""
return _get_user_profile_by_email(WebClientWrapper(client), email)


def get_user_email(client: WebClient, user_id: str) -> str:
"""Gets the user's email."""
user_info = get_user_info_by_id(client, user_id)
Expand Down

0 comments on commit bb98d48

Please sign in to comment.