Files
zulip/zerver/management/commands/deliver_scheduled_emails.py
Prakhar Pratyush 9c9866461a transaction: Add durable=True to the outermost db transactions.
This commit adds `durable=True` to the outermost db transactions
created in the following:
* confirm_email_change
* handle_upload_pre_finish_hook
* deliver_scheduled_emails
* restore_data_from_archive
* do_change_realm_subdomain
* do_create_realm
* do_deactivate_realm
* do_reactivate_realm
* do_delete_user
* do_delete_user_preserving_messages
* create_stripe_customer
* process_initial_upgrade
* do_update_plan
* request_sponsorship
* upload_message_attachment
* register_remote_server
* do_soft_deactivate_users
* maybe_send_batched_emails

It helps to avoid creating unintended savepoints in the future.

This is as a part of our plan to explicitly mark all the
transaction.atomic calls with either 'savepoint=False' or
'durable=True' as required.

* 'savepoint=True' is used in special cases.
2024-11-05 17:58:47 -08:00

57 lines
1.7 KiB
Python

"""\
Send email messages that have been queued for later delivery by
various things (e.g. invitation reminders and welcome emails).
This management command is run via supervisor.
"""
import logging
import time
from typing import Any
from django.conf import settings
from django.db import transaction
from django.utils.timezone import now as timezone_now
from typing_extensions import override
from zerver.lib.logging_util import log_to_file
from zerver.lib.management import ZulipBaseCommand
from zerver.lib.send_email import EmailNotDeliveredError, deliver_scheduled_emails
from zerver.models import ScheduledEmail
## Setup ##
logger = logging.getLogger(__name__)
log_to_file(logger, settings.EMAIL_DELIVERER_LOG_PATH)
class Command(ZulipBaseCommand):
help = """Send emails queued by various parts of Zulip
for later delivery.
Run this command under supervisor.
Usage: ./manage.py deliver_scheduled_emails
"""
@override
def handle(self, *args: Any, **options: Any) -> None:
try:
while True:
with transaction.atomic(durable=True):
job = (
ScheduledEmail.objects.filter(scheduled_timestamp__lte=timezone_now())
.prefetch_related("users")
.select_for_update(skip_locked=True)
.order_by("scheduled_timestamp")
.first()
)
if job:
try:
deliver_scheduled_emails(job)
except EmailNotDeliveredError:
logger.warning("%r not delivered", job)
else:
time.sleep(10)
except KeyboardInterrupt:
pass