Files
Warracker/backend/extensions.py
sassanix 60239bd637 Fix Apprise notification system, scheduler stability, and email configuration
Fixes & Enhancements

* Resolved five critical Apprise notification issues:
  • Ensured configuration reload during scheduled jobs
  • Fixed warranty data fetching for Apprise-only users
  • Refactored notification dispatch logic with dedicated helpers
  • Corrected handler scoping via Flask app context
  • Wrapped scheduler jobs with Flask app context to prevent context errors
  → Verified: Scheduled Apprise notifications now work reliably for "Apprise only" and "Both" channels.

* Added support for SMTP\_FROM\_ADDRESS environment variable, allowing sender address customization independent of SMTP username. (PR #115)

* Fixed duplicate scheduled notifications in multi-worker environments:
  • Strengthened should\_run\_scheduler() logic
  • Now guarantees exactly one scheduler instance across all Gunicorn modes.

* Fixed stale database connection handling in scheduled jobs:
  • Fresh connection acquired each run, properly released via try/finally
  • Eliminates "server closed the connection" errors.

* Definitive scheduler logic fix for all memory modes (ultra-light, optimized, performance):
  • Single-worker runs scheduler if GUNICORN\_WORKER\_ID is unset
  • Multi-worker: only worker 0 runs scheduler.

Impact

* Apprise and Email notifications are now stable, reliable, and production-ready
* No more duplicate or missed notifications across all memory modes
* Improved system efficiency and robustness
2025-08-24 12:34:40 -03:00

78 lines
2.7 KiB
Python

# backend/extensions.py
import logging
from authlib.integrations.flask_client import OAuth
from flask_cors import CORS
from flask_bcrypt import Bcrypt
logger = logging.getLogger(__name__)
# Initialize extensions without app instance
oauth = OAuth()
cors = CORS()
bcrypt = Bcrypt()
babel = None # Will be initialized in initialize_extensions
db_pool = None # Database connection pool
def initialize_extensions(app):
"""Initialize all extensions with the Flask app object."""
global babel, db_pool
logger.info("Initializing Flask extensions...")
# Initialize OAuth
oauth.init_app(app)
logger.info("OAuth initialized")
# Initialize CORS with credentials support
cors.init_app(app, supports_credentials=True)
logger.info("CORS initialized")
# Initialize Bcrypt
bcrypt.init_app(app)
logger.info("Bcrypt initialized")
# Initialize Babel for localization
try:
from .localization import init_babel, get_current_language
babel = init_babel(app)
logger.info("Babel localization initialized successfully")
except ImportError:
try:
from localization import init_babel, get_current_language
babel = init_babel(app)
logger.info("Babel localization initialized successfully")
except ImportError as e:
logger.error(f"Failed to initialize localization: {e}")
babel = None
# Initialize the database connection pool
try:
from .db_handler import init_db_pool
db_pool = init_db_pool()
logger.info("Database connection pool initialized successfully")
except ImportError:
try:
from db_handler import init_db_pool
db_pool = init_db_pool()
logger.info("Database connection pool initialized successfully")
except ImportError as e:
logger.critical(f"CRITICAL: Failed to initialize database pool: {e}")
raise
# Initialize Apprise notification handler
try:
try:
from .apprise_handler import AppriseNotificationHandler
except ImportError:
from apprise_handler import AppriseNotificationHandler
apprise_handler = AppriseNotificationHandler()
app.config['APPRISE_HANDLER'] = apprise_handler
app.config['APPRISE_AVAILABLE'] = True
logger.info("Apprise notification handler initialized successfully")
except ImportError as e:
app.config['APPRISE_HANDLER'] = None
app.config['APPRISE_AVAILABLE'] = False
logger.warning(f"Apprise not available: {e}. Notification features will be disabled.")
logger.info("All extensions initialized successfully")