Remove deprecated backend files and documentation, including Docker configurations, environment variables, and various scripts, to streamline the project structure and eliminate unused components.
This commit is contained in:
1
backend/app/utils/__init__.py
Normal file
1
backend/app/utils/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Utils package for MYP
|
230
backend/app/utils/job_scheduler.py
Normal file
230
backend/app/utils/job_scheduler.py
Normal file
@@ -0,0 +1,230 @@
|
||||
import threading
|
||||
import time
|
||||
import logging
|
||||
from typing import Dict, Callable, Any, List, Optional, Union
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from utils.logging_config import get_logger
|
||||
|
||||
logger = get_logger("scheduler")
|
||||
|
||||
class BackgroundTaskScheduler:
|
||||
"""
|
||||
Ein fortschrittlicher Hintergrund-Task-Scheduler, der registrierbare Worker-Funktionen unterstützt.
|
||||
Tasks können als Platzhalter registriert und später konfiguriert werden.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._tasks: Dict[str, Dict[str, Any]] = {}
|
||||
self._thread: Optional[threading.Thread] = None
|
||||
self._stop_event = threading.Event()
|
||||
self._running = False
|
||||
|
||||
def register_task(self,
|
||||
task_id: str,
|
||||
func: Callable,
|
||||
interval: int = 60,
|
||||
args: List = None,
|
||||
kwargs: Dict = None,
|
||||
enabled: bool = True) -> bool:
|
||||
"""
|
||||
Registriert eine neue Hintergrund-Task.
|
||||
|
||||
Args:
|
||||
task_id: Eindeutige ID für die Task
|
||||
func: Die auszuführende Funktion
|
||||
interval: Intervall in Sekunden zwischen den Ausführungen
|
||||
args: Positionsargumente für die Funktion
|
||||
kwargs: Schlüsselwortargumente für die Funktion
|
||||
enabled: Ob die Task aktiviert sein soll
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich, False wenn die ID bereits existiert
|
||||
"""
|
||||
if task_id in self._tasks:
|
||||
logger.error(f"Task mit ID {task_id} existiert bereits")
|
||||
return False
|
||||
|
||||
self._tasks[task_id] = {
|
||||
"func": func,
|
||||
"interval": interval,
|
||||
"args": args or [],
|
||||
"kwargs": kwargs or {},
|
||||
"enabled": enabled,
|
||||
"last_run": None,
|
||||
"next_run": datetime.now() if enabled else None
|
||||
}
|
||||
|
||||
logger.info(f"Task {task_id} registriert: Intervall {interval}s, Enabled: {enabled}")
|
||||
return True
|
||||
|
||||
def update_task(self,
|
||||
task_id: str,
|
||||
interval: Optional[int] = None,
|
||||
args: Optional[List] = None,
|
||||
kwargs: Optional[Dict] = None,
|
||||
enabled: Optional[bool] = None) -> bool:
|
||||
"""
|
||||
Aktualisiert die Konfiguration einer bestehenden Task.
|
||||
|
||||
Args:
|
||||
task_id: ID der zu aktualisierenden Task
|
||||
interval: Neues Intervall in Sekunden
|
||||
args: Neue Positionsargumente
|
||||
kwargs: Neue Schlüsselwortargumente
|
||||
enabled: Neuer Aktivierungsstatus
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich, False wenn die ID nicht existiert
|
||||
"""
|
||||
if task_id not in self._tasks:
|
||||
logger.error(f"Task mit ID {task_id} existiert nicht")
|
||||
return False
|
||||
|
||||
task = self._tasks[task_id]
|
||||
|
||||
if interval is not None:
|
||||
task["interval"] = interval
|
||||
|
||||
if args is not None:
|
||||
task["args"] = args
|
||||
|
||||
if kwargs is not None:
|
||||
task["kwargs"] = kwargs
|
||||
|
||||
if enabled is not None and enabled != task["enabled"]:
|
||||
task["enabled"] = enabled
|
||||
if enabled:
|
||||
task["next_run"] = datetime.now()
|
||||
else:
|
||||
task["next_run"] = None
|
||||
|
||||
logger.info(f"Task {task_id} aktualisiert: Intervall {task['interval']}s, Enabled: {task['enabled']}")
|
||||
return True
|
||||
|
||||
def remove_task(self, task_id: str) -> bool:
|
||||
"""
|
||||
Entfernt eine Task aus dem Scheduler.
|
||||
|
||||
Args:
|
||||
task_id: ID der zu entfernenden Task
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich, False wenn die ID nicht existiert
|
||||
"""
|
||||
if task_id not in self._tasks:
|
||||
logger.error(f"Task mit ID {task_id} existiert nicht")
|
||||
return False
|
||||
|
||||
del self._tasks[task_id]
|
||||
logger.info(f"Task {task_id} entfernt")
|
||||
return True
|
||||
|
||||
def get_task_info(self, task_id: Optional[str] = None) -> Union[Dict, List[Dict]]:
|
||||
"""
|
||||
Gibt Informationen zu einer Task oder allen Tasks zurück.
|
||||
|
||||
Args:
|
||||
task_id: ID der Task oder None für alle Tasks
|
||||
|
||||
Returns:
|
||||
Dict oder List: Task-Informationen
|
||||
"""
|
||||
if task_id is not None:
|
||||
if task_id not in self._tasks:
|
||||
return {}
|
||||
|
||||
task = self._tasks[task_id]
|
||||
return {
|
||||
"id": task_id,
|
||||
"interval": task["interval"],
|
||||
"enabled": task["enabled"],
|
||||
"last_run": task["last_run"].isoformat() if task["last_run"] else None,
|
||||
"next_run": task["next_run"].isoformat() if task["next_run"] else None
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
"id": tid,
|
||||
"interval": task["interval"],
|
||||
"enabled": task["enabled"],
|
||||
"last_run": task["last_run"].isoformat() if task["last_run"] else None,
|
||||
"next_run": task["next_run"].isoformat() if task["next_run"] else None
|
||||
}
|
||||
for tid, task in self._tasks.items()
|
||||
]
|
||||
|
||||
def start(self) -> bool:
|
||||
"""
|
||||
Startet den Scheduler.
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich gestartet, False wenn bereits läuft
|
||||
"""
|
||||
if self._running:
|
||||
logger.warning("Scheduler läuft bereits")
|
||||
return False
|
||||
|
||||
self._stop_event.clear()
|
||||
self._thread = threading.Thread(target=self._run)
|
||||
self._thread.daemon = True
|
||||
self._thread.start()
|
||||
self._running = True
|
||||
|
||||
logger.info("Scheduler gestartet")
|
||||
return True
|
||||
|
||||
def stop(self) -> bool:
|
||||
"""
|
||||
Stoppt den Scheduler.
|
||||
|
||||
Returns:
|
||||
bool: True wenn erfolgreich gestoppt, False wenn nicht läuft
|
||||
"""
|
||||
if not self._running:
|
||||
logger.warning("Scheduler läuft nicht")
|
||||
return False
|
||||
|
||||
self._stop_event.set()
|
||||
if self._thread:
|
||||
self._thread.join(timeout=5.0)
|
||||
|
||||
self._running = False
|
||||
logger.info("Scheduler gestoppt")
|
||||
return True
|
||||
|
||||
def is_running(self) -> bool:
|
||||
"""
|
||||
Prüft, ob der Scheduler läuft.
|
||||
|
||||
Returns:
|
||||
bool: True wenn der Scheduler läuft, sonst False
|
||||
"""
|
||||
return self._running
|
||||
|
||||
def _run(self) -> None:
|
||||
"""Interne Methode zum Ausführen des Scheduler-Loops."""
|
||||
while not self._stop_event.is_set():
|
||||
now = datetime.now()
|
||||
|
||||
for task_id, task in self._tasks.items():
|
||||
if not task["enabled"] or not task["next_run"]:
|
||||
continue
|
||||
|
||||
if now >= task["next_run"]:
|
||||
logger.info(f"Ausführung von Task {task_id}")
|
||||
|
||||
try:
|
||||
task["func"](*task["args"], **task["kwargs"])
|
||||
logger.info(f"Task {task_id} erfolgreich ausgeführt")
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei Ausführung von Task {task_id}: {str(e)}")
|
||||
|
||||
task["last_run"] = now
|
||||
task["next_run"] = now + timedelta(seconds=task["interval"])
|
||||
|
||||
# 1 Sekunde warten und erneut prüfen
|
||||
self._stop_event.wait(1)
|
||||
|
||||
# Singleton-Instanz
|
||||
scheduler = BackgroundTaskScheduler()
|
101
backend/app/utils/logging_config.py
Normal file
101
backend/app/utils/logging_config.py
Normal file
@@ -0,0 +1,101 @@
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
from typing import Dict
|
||||
from config.settings import (
|
||||
LOG_DIR, LOG_SUBDIRS, LOG_LEVEL, LOG_FORMAT, LOG_DATE_FORMAT,
|
||||
get_log_file, ensure_log_directories
|
||||
)
|
||||
|
||||
# Dictionary zur Speicherung der konfigurierten Logger
|
||||
_loggers: Dict[str, logging.Logger] = {}
|
||||
|
||||
def setup_logging():
|
||||
"""Initialisiert das Logging-System und erstellt alle erforderlichen Verzeichnisse."""
|
||||
ensure_log_directories()
|
||||
|
||||
# Root-Logger konfigurieren
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(getattr(logging, LOG_LEVEL))
|
||||
|
||||
# Alle Handler entfernen
|
||||
for handler in root_logger.handlers[:]:
|
||||
root_logger.removeHandler(handler)
|
||||
|
||||
# Formatter erstellen
|
||||
formatter = logging.Formatter(LOG_FORMAT, LOG_DATE_FORMAT)
|
||||
|
||||
# Console Handler für alle Logs
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(getattr(logging, LOG_LEVEL))
|
||||
console_handler.setFormatter(formatter)
|
||||
root_logger.addHandler(console_handler)
|
||||
|
||||
# File Handler für allgemeine App-Logs
|
||||
app_log_file = get_log_file("app")
|
||||
app_handler = logging.handlers.RotatingFileHandler(
|
||||
app_log_file, maxBytes=10*1024*1024, backupCount=5
|
||||
)
|
||||
app_handler.setLevel(getattr(logging, LOG_LEVEL))
|
||||
app_handler.setFormatter(formatter)
|
||||
root_logger.addHandler(app_handler)
|
||||
|
||||
def get_logger(category: str) -> logging.Logger:
|
||||
"""
|
||||
Gibt einen konfigurierten Logger für eine bestimmte Kategorie zurück.
|
||||
|
||||
Args:
|
||||
category: Log-Kategorie (app, scheduler, auth, jobs, printers, errors)
|
||||
|
||||
Returns:
|
||||
logging.Logger: Konfigurierter Logger
|
||||
"""
|
||||
if category in _loggers:
|
||||
return _loggers[category]
|
||||
|
||||
# Logger erstellen
|
||||
logger = logging.getLogger(f"myp.{category}")
|
||||
logger.setLevel(getattr(logging, LOG_LEVEL))
|
||||
|
||||
# Verhindere doppelte Logs durch Parent-Logger
|
||||
logger.propagate = False
|
||||
|
||||
# Formatter erstellen
|
||||
formatter = logging.Formatter(LOG_FORMAT, LOG_DATE_FORMAT)
|
||||
|
||||
# Console Handler
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(getattr(logging, LOG_LEVEL))
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
# File Handler für spezifische Kategorie
|
||||
log_file = get_log_file(category)
|
||||
file_handler = logging.handlers.RotatingFileHandler(
|
||||
log_file, maxBytes=10*1024*1024, backupCount=5
|
||||
)
|
||||
file_handler.setLevel(getattr(logging, LOG_LEVEL))
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
# Error-Logs zusätzlich in errors.log schreiben
|
||||
if category != "errors":
|
||||
error_log_file = get_log_file("errors")
|
||||
error_handler = logging.handlers.RotatingFileHandler(
|
||||
error_log_file, maxBytes=10*1024*1024, backupCount=5
|
||||
)
|
||||
error_handler.setLevel(logging.ERROR)
|
||||
error_handler.setFormatter(formatter)
|
||||
logger.addHandler(error_handler)
|
||||
|
||||
_loggers[category] = logger
|
||||
return logger
|
||||
|
||||
def log_startup_info():
|
||||
"""Loggt Startup-Informationen."""
|
||||
app_logger = get_logger("app")
|
||||
app_logger.info("=" * 50)
|
||||
app_logger.info("MYP (Manage Your Printers) wird gestartet...")
|
||||
app_logger.info(f"Log-Verzeichnis: {LOG_DIR}")
|
||||
app_logger.info(f"Log-Level: {LOG_LEVEL}")
|
||||
app_logger.info("=" * 50)
|
Reference in New Issue
Block a user