04/17 Update: sends email to each IT Staff from email ingestion ticket
This commit is contained in:
@@ -107,18 +107,34 @@ def create_notification(user_id, notif_type, title, message, ticket_id=None, lin
|
||||
|
||||
def send_email(subject, recipients, html_body):
|
||||
"""
|
||||
Send an email in a background thread so it never blocks the request.
|
||||
Send an email in a background thread so it never blocks the caller.
|
||||
|
||||
Flask-Mail opens an SMTP connection synchronously. Running it in the main
|
||||
request thread means a slow or failing SMTP server delays the entire
|
||||
response — including the WebSocket notification push that follows.
|
||||
Using a daemon thread isolates SMTP failures from the request lifecycle.
|
||||
Using a background thread isolates SMTP failures from the request lifecycle.
|
||||
|
||||
Thread daemon mode
|
||||
------------------
|
||||
When called from a web request context, the thread is spawned as a daemon
|
||||
(daemon=True) so it does not prevent the server process from exiting cleanly.
|
||||
|
||||
When called from an APScheduler background job (no active request context),
|
||||
the thread is spawned as a non-daemon (daemon=False). Daemon threads are
|
||||
killed as soon as the parent thread exits — since the APScheduler job thread
|
||||
finishes quickly, a daemon email thread is terminated before SMTP delivery
|
||||
completes, causing silent email loss. A non-daemon thread survives until
|
||||
the SMTP handshake finishes regardless of the job thread's lifetime.
|
||||
"""
|
||||
from threading import Thread
|
||||
from flask import current_app
|
||||
from flask import current_app, has_request_context
|
||||
|
||||
app = current_app._get_current_object() # real app, not the proxy
|
||||
|
||||
# Determine daemon mode based on whether we are inside a live HTTP request.
|
||||
# APScheduler jobs and other background callers have no request context.
|
||||
is_daemon = has_request_context()
|
||||
|
||||
def _send():
|
||||
with app.app_context():
|
||||
try:
|
||||
@@ -128,7 +144,7 @@ def send_email(subject, recipients, html_body):
|
||||
except Exception as exc:
|
||||
logger.error(f'[EMAIL ERROR] Failed to send "{subject}" to {recipients}: {exc}')
|
||||
|
||||
t = Thread(target=_send, daemon=True)
|
||||
t = Thread(target=_send, daemon=is_daemon)
|
||||
t.start()
|
||||
|
||||
|
||||
@@ -502,6 +518,10 @@ def send_satisfaction_survey(ticket):
|
||||
f'recipient={creator_email}: {exc}', exc_info=True
|
||||
)
|
||||
|
||||
t = Thread(target=_send, daemon=True)
|
||||
# Mirror the daemon-mode logic from send_email(): non-daemon when called
|
||||
# outside a request context (e.g. from the SLA APScheduler job) so the
|
||||
# thread is not killed before SMTP delivery completes.
|
||||
from flask import has_request_context
|
||||
t = Thread(target=_send, daemon=has_request_context())
|
||||
t.start()
|
||||
logger.info(f'[SURVEY] Email thread started for ticket_id={ticket_id}')
|
||||
Reference in New Issue
Block a user