116 Zeilen
3.6 KiB
Python
116 Zeilen
3.6 KiB
Python
"""
|
|
Background scheduler for License Server
|
|
Handles periodic tasks like session cleanup
|
|
"""
|
|
import logging
|
|
from datetime import datetime, timedelta
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
from apscheduler.triggers.interval import IntervalTrigger
|
|
from sqlalchemy import text
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db.database import SessionLocal
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
scheduler = BackgroundScheduler()
|
|
|
|
|
|
def cleanup_expired_sessions():
|
|
"""Clean up sessions that haven't sent heartbeat within timeout period"""
|
|
db: Session = SessionLocal()
|
|
try:
|
|
# Get session timeout from config (default 60 seconds)
|
|
result = db.execute(text("""
|
|
SELECT session_timeout
|
|
FROM client_configs
|
|
WHERE client_name = 'Account Forger'
|
|
""")).first()
|
|
|
|
timeout_seconds = result[0] if result else 60
|
|
|
|
# Find expired sessions
|
|
expired_sessions = db.execute(text(f"""
|
|
SELECT id, license_id, hardware_fingerprint, session_token
|
|
FROM license_sessions
|
|
WHERE ended_at IS NULL
|
|
AND last_heartbeat < NOW() - INTERVAL '{timeout_seconds} seconds'
|
|
""")).fetchall()
|
|
|
|
if expired_sessions:
|
|
logger.info(f"Found {len(expired_sessions)} expired sessions to clean up")
|
|
|
|
# Mark sessions as ended
|
|
for session in expired_sessions:
|
|
db.execute(text("""
|
|
UPDATE license_sessions
|
|
SET ended_at = NOW(), end_reason = 'timeout'
|
|
WHERE id = :session_id
|
|
"""), {"session_id": session[0]})
|
|
|
|
logger.info(f"Ended session {session[0]} for license {session[1]} due to timeout")
|
|
|
|
db.commit()
|
|
logger.info(f"Successfully cleaned up {len(expired_sessions)} expired sessions")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error cleaning up sessions: {str(e)}")
|
|
db.rollback()
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def cleanup_old_sessions():
|
|
"""Remove old ended sessions from database (older than 30 days)"""
|
|
db: Session = SessionLocal()
|
|
try:
|
|
result = db.execute(text("""
|
|
DELETE FROM license_sessions
|
|
WHERE ended_at IS NOT NULL
|
|
AND ended_at < NOW() - INTERVAL '30 days'
|
|
"""))
|
|
|
|
if result.rowcount > 0:
|
|
db.commit()
|
|
logger.info(f"Cleaned up {result.rowcount} old sessions")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error cleaning up old sessions: {str(e)}")
|
|
db.rollback()
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
def init_scheduler():
|
|
"""Initialize and start the background scheduler"""
|
|
# Add job to cleanup expired sessions every 30 seconds
|
|
scheduler.add_job(
|
|
func=cleanup_expired_sessions,
|
|
trigger=IntervalTrigger(seconds=30),
|
|
id='cleanup_expired_sessions',
|
|
name='Cleanup expired sessions',
|
|
replace_existing=True
|
|
)
|
|
|
|
# Add job to cleanup old sessions daily at 3 AM
|
|
scheduler.add_job(
|
|
func=cleanup_old_sessions,
|
|
trigger='cron',
|
|
hour=3,
|
|
minute=0,
|
|
id='cleanup_old_sessions',
|
|
name='Cleanup old sessions',
|
|
replace_existing=True
|
|
)
|
|
|
|
scheduler.start()
|
|
logger.info("Background scheduler started")
|
|
logger.info("- Session cleanup runs every 30 seconds")
|
|
logger.info("- Old session cleanup runs daily at 3:00 AM")
|
|
|
|
|
|
def shutdown_scheduler():
|
|
"""Shutdown the scheduler gracefully"""
|
|
if scheduler.running:
|
|
scheduler.shutdown()
|
|
logger.info("Background scheduler stopped") |