zulip_update: Catch and carry on if a realm fails.

It is better to log the exception and _try_ all realms, than to fail
early due to a bad realm and fail to notify the rest.
This commit is contained in:
Alex Vandiver 2024-05-24 15:19:24 +00:00 committed by Tim Abbott
parent 5c2fd1de5a
commit 174ae2b409
2 changed files with 87 additions and 86 deletions

View File

@ -40,7 +40,7 @@ from zerver.lib.user_counts import realm_user_count_by_role
from zerver.lib.user_groups import create_system_user_groups_for_realm
from zerver.lib.user_message import UserMessageLite, bulk_insert_ums
from zerver.lib.utils import generate_api_key, process_list_in_batches
from zerver.lib.zulip_update_announcements import send_zulip_update_announcements
from zerver.lib.zulip_update_announcements import send_zulip_update_announcements_to_realm
from zerver.models import (
AlertWord,
Attachment,
@ -1559,7 +1559,9 @@ def do_import_realm(import_dir: Path, subdomain: str, processes: int = 1) -> Rea
realm=realm, event_type=RealmAuditLog.REALM_EXPORTED, acting_user=None
).exists()
if not is_realm_imported_from_other_zulip_server:
send_zulip_update_announcements(skip_delay=False, realm_imported_from_other_product=realm)
send_zulip_update_announcements_to_realm(
realm, skip_delay=False, realm_imported_from_other_product=True
)
return realm

View File

@ -1,3 +1,4 @@
import logging
from dataclasses import dataclass
from datetime import timedelta
from typing import List, Optional
@ -220,76 +221,74 @@ def send_messages_and_update_level(
realm.save(update_fields=["zulip_update_announcements_level"])
def send_zulip_update_announcements(
skip_delay: bool, realm_imported_from_other_product: Optional[Realm] = None
def send_zulip_update_announcements(skip_delay: bool) -> None:
latest_zulip_update_announcements_level = get_latest_zulip_update_announcements_level()
for realm in get_realms_behind_zulip_update_announcements_level(
level=latest_zulip_update_announcements_level
):
try:
send_zulip_update_announcements_to_realm(realm, skip_delay)
except Exception as e: # nocoverage
logging.exception(e)
def send_zulip_update_announcements_to_realm(
realm: Realm, skip_delay: bool, realm_imported_from_other_product: bool = False
) -> None:
latest_zulip_update_announcements_level = get_latest_zulip_update_announcements_level()
# Refresh the realm from the database and check its
# properties, to protect against racing with another copy of
# ourself.
realm.refresh_from_db()
realm_zulip_update_announcements_level = realm.zulip_update_announcements_level
assert (
realm_zulip_update_announcements_level is None
or realm_zulip_update_announcements_level < latest_zulip_update_announcements_level
)
if realm_imported_from_other_product:
realms = [realm_imported_from_other_product]
else:
realms = list(
get_realms_behind_zulip_update_announcements_level(
level=latest_zulip_update_announcements_level
)
)
sender = get_system_bot(settings.NOTIFICATION_BOT, realm.id)
for realm in realms:
# Refresh the realm from the database and check its
# properties, to protect against racing with another copy of
# ourself.
realm.refresh_from_db()
realm_zulip_update_announcements_level = realm.zulip_update_announcements_level
assert (
realm_zulip_update_announcements_level is None
or realm_zulip_update_announcements_level < latest_zulip_update_announcements_level
)
messages = []
new_zulip_update_announcements_level = None
sender = get_system_bot(settings.NOTIFICATION_BOT, realm.id)
messages = []
new_zulip_update_announcements_level = None
if realm_zulip_update_announcements_level is None:
# This realm predates the zulip update announcements feature, or
# was imported from another product (Slack, Mattermost, etc.).
# Group DM the administrators to set or verify the stream for
# zulip update announcements.
group_direct_message = internal_prep_group_direct_message_for_old_realm(realm, sender)
messages = [group_direct_message]
if realm_imported_from_other_product:
new_zulip_update_announcements_level = latest_zulip_update_announcements_level
else:
new_zulip_update_announcements_level = 0
elif realm.zulip_update_announcements_stream is None:
# We wait for a week after sending group DMs to let admins configure
# stream for zulip update announcements. After that, they miss updates
# until they don't configure.
if not is_group_direct_message_sent_to_admins_within_days(realm, days=7):
new_zulip_update_announcements_level = latest_zulip_update_announcements_level
if realm_zulip_update_announcements_level is None:
# This realm predates the zulip update announcements feature, or
# was imported from another product (Slack, Mattermost, etc.).
# Group DM the administrators to set or verify the stream for
# zulip update announcements.
group_direct_message = internal_prep_group_direct_message_for_old_realm(realm, sender)
messages = [group_direct_message]
if realm_imported_from_other_product:
new_zulip_update_announcements_level = latest_zulip_update_announcements_level
else:
# Wait for 24 hours after sending group DM to allow admins to change the
# stream for zulip update announcements from it's default value if desired.
if (
realm_zulip_update_announcements_level == 0
and is_group_direct_message_sent_to_admins_within_days(realm, days=1)
and not skip_delay
):
continue
new_zulip_update_announcements_level = 0
elif realm.zulip_update_announcements_stream is None:
# We wait for a week after sending group DMs to let admins configure
# stream for zulip update announcements. After that, they miss updates
# until they don't configure.
if not is_group_direct_message_sent_to_admins_within_days(realm, days=7):
new_zulip_update_announcements_level = latest_zulip_update_announcements_level
else:
# Wait for 24 hours after sending group DM to allow admins to change the
# stream for zulip update announcements from it's default value if desired.
if (
realm_zulip_update_announcements_level == 0
and is_group_direct_message_sent_to_admins_within_days(realm, days=1)
and not skip_delay
):
return
# Send an introductory message just before the first update message.
with override_language(realm.default_language):
topic_name = str(realm.ZULIP_UPDATE_ANNOUNCEMENTS_TOPIC_NAME)
# Send an introductory message just before the first update message.
with override_language(realm.default_language):
topic_name = str(realm.ZULIP_UPDATE_ANNOUNCEMENTS_TOPIC_NAME)
stream = realm.zulip_update_announcements_stream
assert stream.recipient_id is not None
topic_has_messages = messages_for_topic(
realm.id, stream.recipient_id, topic_name
).exists()
stream = realm.zulip_update_announcements_stream
assert stream.recipient_id is not None
topic_has_messages = messages_for_topic(realm.id, stream.recipient_id, topic_name).exists()
if not topic_has_messages:
content_of_introductory_message = (
"""
if not topic_has_messages:
content_of_introductory_message = (
"""
To help you learn about new features and configuration options,
this topic will receive messages about important changes in Zulip.
@ -298,29 +297,29 @@ You can read these update messages whenever it's convenient, or
If your organization does not want to receive these announcements,
they can be disabled. [Learn more]({zulip_update_announcements_help_url}).
"""
).format(
zulip_update_announcements_help_url="/help/configure-automated-notices#zulip-update-announcements",
mute_topic_help_url="/help/mute-a-topic",
)
messages = [
internal_prep_stream_message(
sender,
stream,
topic_name,
remove_single_newlines(content_of_introductory_message),
)
]
messages.extend(
internal_prep_zulip_update_announcements_stream_messages(
current_level=realm_zulip_update_announcements_level,
latest_level=latest_zulip_update_announcements_level,
sender=sender,
realm=realm,
)
).format(
zulip_update_announcements_help_url="/help/configure-automated-notices#zulip-update-announcements",
mute_topic_help_url="/help/mute-a-topic",
)
messages = [
internal_prep_stream_message(
sender,
stream,
topic_name,
remove_single_newlines(content_of_introductory_message),
)
]
new_zulip_update_announcements_level = latest_zulip_update_announcements_level
messages.extend(
internal_prep_zulip_update_announcements_stream_messages(
current_level=realm_zulip_update_announcements_level,
latest_level=latest_zulip_update_announcements_level,
sender=sender,
realm=realm,
)
)
if new_zulip_update_announcements_level is not None:
send_messages_and_update_level(realm, new_zulip_update_announcements_level, messages)
new_zulip_update_announcements_level = latest_zulip_update_announcements_level
if new_zulip_update_announcements_level is not None:
send_messages_and_update_level(realm, new_zulip_update_announcements_level, messages)