
This commit introduces several improvements to the application configuration and logging mechanisms, including: - Added a new `REDIS_URL` configuration option in the production environment template for easier Redis setup. - Implemented a soft delete method in the `UserManager` class to anonymize user data while maintaining referential integrity. - Enhanced session secret management to ensure a secure fallback in non-production environments. - Introduced a `PiiRedactionFilter` to loggers for redacting sensitive information from logs. - Added rate limiting middleware to control API request rates and prevent abuse. These changes aim to improve security, maintainability, and user data protection within the application.
69 lines
2.0 KiB
Python
69 lines
2.0 KiB
Python
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
from apscheduler.jobstores.memory import MemoryJobStore
|
|
from apscheduler.executors.pool import ThreadPoolExecutor
|
|
from apscheduler.triggers.cron import CronTrigger
|
|
from app.config import settings
|
|
from app.jobs.recurring_expenses import generate_recurring_expenses
|
|
from app.db.session import async_session
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
jobstores = {
|
|
'default': MemoryJobStore()
|
|
}
|
|
|
|
# Run scheduled jobs on a separate small thread pool to keep event loop free
|
|
executors = {
|
|
'default': ThreadPoolExecutor(5)
|
|
}
|
|
|
|
job_defaults = {
|
|
'coalesce': False,
|
|
'max_instances': 1
|
|
}
|
|
|
|
scheduler = AsyncIOScheduler(
|
|
jobstores=jobstores,
|
|
executors=executors,
|
|
job_defaults=job_defaults,
|
|
timezone='UTC'
|
|
)
|
|
|
|
async def run_recurring_expenses_job():
|
|
"""Wrapper function to run the recurring expenses job with a database session.
|
|
|
|
This function is used to generate recurring expenses for the user.
|
|
"""
|
|
try:
|
|
async with async_session() as session:
|
|
await generate_recurring_expenses(session)
|
|
except Exception as e:
|
|
logger.error(f"Error running recurring expenses job: {str(e)}")
|
|
raise
|
|
|
|
def init_scheduler():
|
|
"""Initialize and start the scheduler."""
|
|
try:
|
|
scheduler.add_job(
|
|
run_recurring_expenses_job,
|
|
trigger=CronTrigger(hour=0, minute=0), # Run at midnight UTC
|
|
id='generate_recurring_expenses',
|
|
name='Generate Recurring Expenses',
|
|
replace_existing=True
|
|
)
|
|
|
|
scheduler.start()
|
|
logger.info("Scheduler started successfully")
|
|
except Exception as e:
|
|
logger.error(f"Error initializing scheduler: {str(e)}")
|
|
raise
|
|
|
|
def shutdown_scheduler():
|
|
"""Shutdown the scheduler gracefully."""
|
|
try:
|
|
scheduler.shutdown()
|
|
logger.info("Scheduler shut down successfully")
|
|
except Exception as e:
|
|
logger.error(f"Error shutting down scheduler: {str(e)}")
|
|
raise |