Potentially fixed daily report

This commit is contained in:
Jonas Linter
2025-10-16 10:39:43 +02:00
parent 0753d1fc1d
commit 90e253b950
2 changed files with 44 additions and 6 deletions

View File

@@ -299,6 +299,22 @@ async def lifespan(app: FastAPI):
report_scheduler.set_stats_collector(stats_collector.collect_stats)
_LOGGER.info("Stats collector initialized and hooked up to report scheduler")
# Send a test daily report on startup for testing
_LOGGER.info("Sending test daily report on startup")
try:
stats = await stats_collector.collect_stats()
success = await email_service.send_daily_report(
recipients=report_scheduler.recipients,
stats=stats,
errors=None,
)
if success:
_LOGGER.info("Test daily report sent successfully on startup")
else:
_LOGGER.error("Failed to send test daily report on startup")
except Exception:
_LOGGER.exception("Error sending test daily report on startup")
# Start daily report scheduler
report_scheduler.start()
_LOGGER.info("Daily report scheduler started")
@@ -320,6 +336,11 @@ async def lifespan(app: FastAPI):
email_handler.close()
_LOGGER.info("Email alert handler closed")
# Shutdown email service thread pool
if email_service:
email_service.shutdown()
_LOGGER.info("Email service shut down")
# Dispose engine
await engine.dispose()
_LOGGER.info("Application shutdown complete")
@@ -711,6 +732,9 @@ async def process_generic_webhook_submission(
name_prefix = form_data.get("anrede")
language = form_data.get("sprache", "de")[:2]
user_comment = form_data.get("nachricht", "")
plz = form_data.get("plz", "")
city = form_data.get("stadt", "")
country = form_data.get("land", "")
# Parse dates - handle DD.MM.YYYY format
start_date_str = form_data.get("anreise")
@@ -790,9 +814,9 @@ async def process_generic_webhook_submission(
"phone": phone_number if phone_number else None,
"email_newsletter": False,
"address_line": None,
"city_name": None,
"postal_code": None,
"country_code": None,
"city_name": city if city else None,
"postal_code": plz if plz else None,
"country_code": country if country else None,
"gender": None,
"birth_date": None,
"language": language,

View File

@@ -7,6 +7,7 @@ including error alerts and daily reports.
import asyncio
import smtplib
import ssl
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
@@ -74,7 +75,9 @@ class EmailService:
"""
self.config = config
self._executor = None # Lazy-initialized thread pool for blocking SMTP
# Create dedicated thread pool for SMTP operations (max 2 threads is enough for email)
# This prevents issues with default executor in multi-process environments
self._executor = ThreadPoolExecutor(max_workers=2, thread_name_prefix="smtp-")
async def send_email(
self,
@@ -114,9 +117,9 @@ class EmailService:
if html_body:
msg.attach(MIMEText(html_body, "html"))
# Send email in thread pool (SMTP is blocking)
# Send email in dedicated thread pool (SMTP is blocking)
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, self._send_smtp, msg, recipients)
await loop.run_in_executor(self._executor, self._send_smtp, msg, recipients)
_LOGGER.info("Email sent successfully to %s: %s", recipients, subject)
return True
@@ -333,6 +336,17 @@ class EmailService:
return html
def shutdown(self) -> None:
"""Shutdown the email service and clean up thread pool.
This should be called during application shutdown to ensure
proper cleanup of the thread pool executor.
"""
if self._executor:
_LOGGER.info("Shutting down email service thread pool")
self._executor.shutdown(wait=True, cancel_futures=False)
_LOGGER.info("Email service thread pool shut down complete")
def create_email_service(config: dict[str, Any]) -> EmailService | None:
"""Create an email service from configuration.