diff options
author | Trygve Aaberge <trygveaa@gmail.com> | 2024-03-28 23:43:50 +0100 |
---|---|---|
committer | Trygve Aaberge <trygveaa@gmail.com> | 2024-03-29 00:00:15 +0100 |
commit | 0b5069e600b6fbe72affed97f0b36ef923ba4072 (patch) | |
tree | f47eba1ab153648e6e24749bc89fb8dfb27286bb | |
parent | ec503d0935cbc171fbe7762a83c36a0e1160efa7 (diff) | |
download | wee-slack-0b5069e600b6fbe72affed97f0b36ef923ba4072.tar.gz |
Retry fetching users with fewer users on errors
Apparently it varies how many users can be fetched in one request with
the users.info method. I have had successful requests with 4096 users,
while some people have reported getting HTTP 500 when fetching 1000
users and one person got an error response with error `too_many_users`
when fetching 500 users.
So when we get either of those errors, reduce the number of users we
fetch in one request and try again until it works or the number of users
has been reduced to 1.
Fixes #924
-rw-r--r-- | slack/slack_api.py | 38 | ||||
-rw-r--r-- | slack/slack_workspace.py | 1 |
2 files changed, 34 insertions, 5 deletions
diff --git a/slack/slack_api.py b/slack/slack_api.py index d3e52e4..b0ef14d 100644 --- a/slack/slack_api.py +++ b/slack/slack_api.py @@ -12,7 +12,7 @@ from typing import ( ) from urllib.parse import urlencode -from slack.error import SlackApiError +from slack.error import HttpError, SlackApiError from slack.http import http_request from slack.shared import shared from slack.slack_message import SlackTs @@ -38,8 +38,10 @@ if TYPE_CHECKING: from slack_api.slack_usergroups_info import SlackUsergroupsInfoResponse from slack_api.slack_users_conversations import SlackUsersConversationsResponse from slack_api.slack_users_info import ( + SlackUserInfo, SlackUserInfoResponse, SlackUsersInfoResponse, + SlackUsersInfoSuccessResponse, ) from slack_api.slack_users_prefs import SlackUsersPrefsGetResponse from slack_edgeapi.slack_usergroups_info import SlackEdgeUsergroupsInfoResponse @@ -277,14 +279,40 @@ class SlackApi(SlackApiCommon): raise SlackApiError(self.workspace, method, response, params) return response - async def fetch_users_info(self, user_ids: Iterable[str]): + async def fetch_users_info( + self, user_ids: Iterable[str] + ) -> SlackUsersInfoSuccessResponse[SlackUserInfo]: responses = await gather( *( self._fetch_users_info_without_splitting(user_ids_batch) - for user_ids_batch in chunked(user_ids, 500) - ) + for user_ids_batch in chunked( + user_ids, self.workspace.max_users_per_fetch_request + ) + ), + return_exceptions=True, ) - users = list(chain(*(response["users"] for response in responses))) + + errors = [r for r in responses if isinstance(r, BaseException)] + if errors: + if ( + any( + # The users.info method may respond with 500 if we request too many users in one request + (isinstance(e, HttpError) and e.http_status_code == 500) + or ( + isinstance(e, SlackApiError) + and e.response["error"] == "too_many_users" + ) + for e in errors + ) + and self.workspace.max_users_per_fetch_request > 1 + ): + self.workspace.max_users_per_fetch_request //= 2 + return await self.fetch_users_info(user_ids) + else: + raise errors[0] + + success_responses = [r for r in responses if not isinstance(r, BaseException)] + users = list(chain(*(response["users"] for response in success_responses))) response: SlackUsersInfoResponse = {"ok": True, "users": users} return response diff --git a/slack/slack_workspace.py b/slack/slack_workspace.py index 99bd8aa..a1289a0 100644 --- a/slack/slack_workspace.py +++ b/slack/slack_workspace.py @@ -219,6 +219,7 @@ class SlackWorkspace: self.usergroups = SlackUsergroups(self) self.muted_channels: Set[str] = set() self.custom_emojis: Dict[str, str] = {} + self.max_users_per_fetch_request = 512 def __repr__(self): return f"{self.__class__.__name__}({self.name})" |