# What this PR does - Fixes issue with slack channels sync periodic tasks when we get slack rate limit exception. - Adds check for active task id to avoid starting multiple tasks for one slack team. Collecting channels for slack for some teams causes rate limit exception, which causes the task to restart and start collecting slack channels from the beginning. This PR adds new paginated api call and refactors the slack channel sync task to continue collect data after rate limit from the step before it was raised using `cursor` value from the slack response. ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [ ] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required) --------- Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
71 lines
2.5 KiB
Python
71 lines
2.5 KiB
Python
from datetime import datetime
|
|
from textwrap import wrap
|
|
|
|
from apps.slack.slack_client import SlackClientWithErrorHandling
|
|
from apps.slack.slack_client.exceptions import SlackAPIException
|
|
|
|
|
|
def create_message_blocks(text):
|
|
"""This function checks text and return blocks
|
|
|
|
Maximum length for the text in section is 3000 characters and
|
|
we can include up to 50 blocks in each message.
|
|
https://api.slack.com/reference/block-kit/blocks#section
|
|
|
|
:param str text: Text for message blocks
|
|
:return list blocks: Blocks list
|
|
"""
|
|
|
|
if len(text) <= 3000:
|
|
blocks = [{"type": "section", "text": {"type": "mrkdwn", "text": text}}]
|
|
else:
|
|
splitted_text_list = text.split("```\n")
|
|
|
|
if len(splitted_text_list) > 1:
|
|
splitted_text_list.pop()
|
|
|
|
blocks = []
|
|
|
|
for splitted_text in splitted_text_list:
|
|
if len(splitted_text) > 2996:
|
|
# too long text case
|
|
text_list = wrap(
|
|
splitted_text, 2994, expand_tabs=False, replace_whitespace=False, break_long_words=False
|
|
)
|
|
|
|
blocks.append({"type": "section", "text": {"type": "mrkdwn", "text": f"{text_list[0]}```"}})
|
|
|
|
for text_item in text_list[1:]:
|
|
blocks.append(
|
|
{"type": "section", "text": {"type": "mrkdwn", "text": f'```{text_item.strip("```")}```'}}
|
|
)
|
|
else:
|
|
blocks.append({"type": "section", "text": {"type": "mrkdwn", "text": splitted_text + "```\n"}})
|
|
|
|
return blocks
|
|
|
|
|
|
def post_message_to_channel(organization, channel_id, text):
|
|
if organization.slack_team_identity:
|
|
slack_client = SlackClientWithErrorHandling(organization.slack_team_identity.bot_access_token)
|
|
try:
|
|
slack_client.api_call("chat.postMessage", channel=channel_id, text=text)
|
|
except SlackAPIException as e:
|
|
if e.response["error"] == "channel_not_found":
|
|
pass
|
|
else:
|
|
raise e
|
|
|
|
|
|
def format_datetime_to_slack(timestamp, format="date_short"):
|
|
fallback = datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M (UTC)")
|
|
return f"<!date^{timestamp}^{{{format}}} {{time}}|{fallback}>"
|
|
|
|
|
|
def get_cache_key_update_incident_slack_message(alert_group_pk):
|
|
CACHE_KEY_PREFIX = "update_incident_slack_message"
|
|
return f"{CACHE_KEY_PREFIX}_{alert_group_pk}"
|
|
|
|
|
|
def get_populate_slack_channel_task_id_key(slack_team_identity_id):
|
|
return f"SLACK_CHANNELS_TASK_ID_TEAM_{slack_team_identity_id}"
|