Skip to content

Commit 0639d8b

Browse files
committed
Handle rate limit errors from Slack on new alert creation
1 parent 8b0e4f2 commit 0639d8b

File tree

1 file changed

+35
-16
lines changed

1 file changed

+35
-16
lines changed

apps/webapp/app/presenters/v3/NewAlertChannelPresenter.server.ts

+35-16
Original file line numberDiff line numberDiff line change
@@ -100,28 +100,47 @@ async function getSlackChannelsForToken(integration: AuthenticatableIntegration)
100100

101101
type Channels = Awaited<ReturnType<WebClient["conversations"]["list"]>>["channels"];
102102

103-
async function getSlackConversationsPage(client: WebClient, nextCursor?: string) {
104-
return client.conversations.list({
105-
types: "public_channel,private_channel",
106-
exclude_archived: true,
107-
cursor: nextCursor,
108-
});
109-
}
110-
111103
async function getAllSlackConversations(client: WebClient) {
112104
let nextCursor: string | undefined = undefined;
113105
let channels: Channels = [];
114106

115-
do {
116-
const response = await getSlackConversationsPage(client, nextCursor);
117-
118-
if (!response.ok) {
119-
throw new Error(`Failed to get channels: ${response.error}`);
107+
try {
108+
do {
109+
// The `tryCatch` util runs into a type error due to self referencing.
110+
// So we fall back to a good old try/catch block here.
111+
const response = await client.conversations.list({
112+
types: "public_channel,private_channel",
113+
exclude_archived: true,
114+
cursor: nextCursor,
115+
limit: 999,
116+
});
117+
118+
channels = channels.concat(response.channels ?? []);
119+
nextCursor = response.response_metadata?.next_cursor;
120+
} while (nextCursor);
121+
} catch (error) {
122+
if (error && isSlackError(error) && error.data.error === "ratelimited") {
123+
logger.warn("Rate limiting issue occurred while fetching Slack channels", {
124+
error,
125+
});
126+
127+
// This is a workaround to the current way we handle Slack channels for creating alerts.
128+
// For workspaces with a lot of channels (>10000) we might hit the rate limit for this slack endpoint,
129+
// as multiple requests are needed to fetch all channels.
130+
// We use the largest allowed page size of 999 to reduce the chance of hitting the rate limit.
131+
132+
// This is mainly due to workspaces with a large number of archived channels,
133+
// which this slack endpoint unfortunately filters out only after fetching the page of channels without applying any filters first.
134+
// https://api.slack.com/methods/conversations.list#markdown
135+
136+
// We expect most workspaces not to run into this issue, but if they do, we at least return some channels.
137+
// In the future, we might revisit the way we handle Slack channels and cache them on our side to support
138+
// proper searching. Until then, we track occurrences of this issue using a metric.
139+
return channels;
120140
}
121141

122-
channels = channels.concat(response.channels ?? []);
123-
nextCursor = response.response_metadata?.next_cursor;
124-
} while (nextCursor);
142+
throw error;
143+
}
125144

126145
return channels;
127146
}

0 commit comments

Comments
 (0)