Add latest changes
Dieser Commit ist enthalten in:
116
v2_lizenzserver/app/core/scheduler.py
Normale Datei
116
v2_lizenzserver/app/core/scheduler.py
Normale Datei
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
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")
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren