app.py aktualisiert
This commit is contained in:
73
app.py
73
app.py
@@ -1,9 +1,11 @@
|
|||||||
# app.py (v2.1 - Final für Docker)
|
# app.py (v2.1 - mit Job-Manager)
|
||||||
from flask import Flask, jsonify, request
|
from flask import Flask, jsonify, request
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import uuid
|
||||||
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pyngrok import ngrok, conf
|
from pyngrok import ngrok, conf
|
||||||
from config import Config
|
from config import Config
|
||||||
@@ -11,32 +13,28 @@ from config import Config
|
|||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# Der Pfad, in dem sich der Code im Container befindet
|
STATUS_DIR = "job_status"
|
||||||
# (muss mit WORKDIR im Dockerfile übereinstimmen)
|
os.makedirs(STATUS_DIR, exist_ok=True)
|
||||||
APP_DIR = "/code"
|
|
||||||
|
|
||||||
SCRIPT_MAP = {
|
SCRIPT_MAP = {
|
||||||
"run_duplicate_check": {"script": "duplicate_checker.py", "args": []},
|
"run_duplicate_check": {"script": "duplicate_checker.py", "args": []},
|
||||||
"run_reclassify_branches": {"script": "brancheneinstufung2.py", "args": ["--mode", "reclassify_branches"]},
|
"run_reclassify_branches": {"script": "brancheneinstufung2.py", "args": ["--mode", "reclassify_branches"]},
|
||||||
# ... fügen Sie hier bei Bedarf brancheneinstufung2.py hinzu
|
"run_predict_technicians": {"script": "brancheneinstufung2.py", "args": ["--mode", "predict_technicians"]},
|
||||||
}
|
}
|
||||||
|
|
||||||
def setup_ngrok():
|
def setup_ngrok():
|
||||||
"""Konfiguriert und startet den ngrok-Tunnel."""
|
# ... (Ihre ngrok-Setup-Funktion bleibt unverändert)
|
||||||
try:
|
try:
|
||||||
authtoken = os.environ.get("NGROK_AUTHTOKEN")
|
authtoken = os.environ.get("NGROK_AUTHTOKEN")
|
||||||
if not authtoken:
|
if not authtoken:
|
||||||
if os.path.exists("ngrok_authtoken.txt"):
|
if os.path.exists("ngrok_authtoken.txt"):
|
||||||
with open("ngrok_authtoken.txt", "r") as f: authtoken = f.read().strip()
|
with open("ngrok_authtoken.txt", "r") as f: authtoken = f.read().strip()
|
||||||
|
|
||||||
if not authtoken:
|
if not authtoken:
|
||||||
logging.error("NGROK_AUTHTOKEN nicht gefunden. Tunnel kann nicht gestartet werden.")
|
logging.error("NGROK_AUTHTOKEN nicht gefunden.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
conf.get_default().auth_token = authtoken
|
conf.get_default().auth_token = authtoken
|
||||||
public_url = ngrok.connect(8080, "http")
|
public_url = ngrok.connect(8080, "http")
|
||||||
logging.info(f"!!! Ngrok-Tunnel gestartet: {public_url} !!!")
|
logging.info(f"!!! Ngrok-Tunnel gestartet: {public_url} !!!")
|
||||||
logging.info("!!! Bitte diese URL im Google Apps Script eintragen. !!!")
|
|
||||||
return public_url
|
return public_url
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Fehler beim Starten von ngrok: {e}")
|
logging.error(f"Fehler beim Starten von ngrok: {e}")
|
||||||
@@ -44,60 +42,51 @@ def setup_ngrok():
|
|||||||
|
|
||||||
@app.route('/run-script', methods=['POST'])
|
@app.route('/run-script', methods=['POST'])
|
||||||
def run_script():
|
def run_script():
|
||||||
"""
|
"""Startet ein Skript als Hintergrundprozess und verfolgt es über eine Job-ID."""
|
||||||
Startet ein Skript als Hintergrundprozess.
|
|
||||||
Finale, robuste Version mit absoluten Pfaden.
|
|
||||||
"""
|
|
||||||
action = "unknown"
|
|
||||||
try:
|
try:
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
action = data.get('action')
|
action = data.get('action')
|
||||||
|
|
||||||
if not action or action not in SCRIPT_MAP:
|
if not action or action not in SCRIPT_MAP:
|
||||||
return jsonify({"status": "error", "message": "Ungültige Aktion."}), 400
|
return jsonify({"status": "error", "message": "Ungültige Aktion."}), 400
|
||||||
|
|
||||||
script_config = SCRIPT_MAP[action]
|
script_config = SCRIPT_MAP[action]
|
||||||
script_name = script_config["script"]
|
script_name = script_config["script"]
|
||||||
|
|
||||||
# ENTSCHEIDENDER FIX: Finde den Pfad relativ zu DIESER app.py Datei
|
# Job-ID generieren und als Argument übergeben
|
||||||
# __file__ ist der Pfad zur aktuell laufenden Datei (app.py)
|
job_id = str(uuid.uuid4())
|
||||||
# os.path.dirname(__file__) ist der Ordner, in dem app.py liegt (/app im Container)
|
command = [sys.executable, script_name] + script_config["args"] + ["--job-id", job_id]
|
||||||
|
|
||||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
script_path = os.path.join(script_dir, script_name)
|
|
||||||
|
|
||||||
if not os.path.exists(script_path):
|
|
||||||
logging.error(f"Skript unter dem Pfad '{script_path}' NICHT GEFUNDEN.")
|
|
||||||
return jsonify({"status": "error", "message": f"Server-Fehler: Skript '{script_name}' nicht gefunden."}), 500
|
|
||||||
|
|
||||||
logging.info(f"Aktion '{action}' empfangen. Starte Skript: '{script_path}'...")
|
|
||||||
|
|
||||||
python_executable = sys.executable
|
|
||||||
command = [python_executable, script_path] + script_config["args"]
|
|
||||||
|
|
||||||
log_dir = os.path.join(script_dir, "Log")
|
log_dir = os.path.join(script_dir, "Log")
|
||||||
os.makedirs(log_dir, exist_ok=True)
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||||
process_log_path = os.path.join(log_dir, f"{timestamp}_{action}.log")
|
process_log_path = os.path.join(log_dir, f"{timestamp}_{action}_{job_id[:8]}.log")
|
||||||
|
|
||||||
with open(process_log_path, 'w') as log_file:
|
with open(process_log_path, 'w') as log_file:
|
||||||
subprocess.Popen(
|
subprocess.Popen(command, cwd=script_dir, stdout=log_file, stderr=log_file)
|
||||||
command,
|
|
||||||
# Wir müssen das Arbeitsverzeichnis nicht mehr setzen, da wir absolute Pfade verwenden
|
|
||||||
stdout=log_file,
|
|
||||||
stderr=log_file
|
|
||||||
)
|
|
||||||
|
|
||||||
return jsonify({"status": "success", "message": f"Aktion '{action}' gestartet. Log wird in '{process_log_path}' geschrieben."}), 200
|
# Erstelle eine initiale Statusdatei
|
||||||
|
status_file = os.path.join(STATUS_DIR, f"{job_id}.json")
|
||||||
|
with open(status_file, 'w') as f:
|
||||||
|
json.dump({
|
||||||
|
"action": action, "status": "Gestartet",
|
||||||
|
"start_time": datetime.now().isoformat(),
|
||||||
|
"progress": "Prozess wird initialisiert..."
|
||||||
|
}, f)
|
||||||
|
|
||||||
|
return jsonify({"status": "success", "message": f"Aktion '{action}' gestartet."}), 200
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(f"Kritischer Fehler in der run_script-Route bei Aktion '{action}': {e}", exc_info=True)
|
logging.error(f"Fehler in run_script: {e}", exc_info=True)
|
||||||
return jsonify({"status": "error", "message": f"Server-Fehler: {str(e)}"}), 500
|
return jsonify({"status": "error", "message": str(e)}), 500
|
||||||
|
|
||||||
|
# --- NEUE FUNKTION ---
|
||||||
@app.route('/get-status', methods=['GET'])
|
@app.route('/get-status', methods=['GET'])
|
||||||
def get_status():
|
def get_status():
|
||||||
"""Liest alle Job-Status-Dateien und gibt den aktuellen Stand zurück."""
|
"""Liest alle Job-Status-Dateien und gibt den aktuellen Stand zurück."""
|
||||||
all_statuses = []
|
all_statuses = []
|
||||||
for filename in os.listdir(STATUS_DIR):
|
for filename in sorted(os.listdir(STATUS_DIR), reverse=True): # Neueste zuerst
|
||||||
if filename.endswith(".json"):
|
if filename.endswith(".json"):
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(STATUS_DIR, filename), 'r') as f:
|
with open(os.path.join(STATUS_DIR, filename), 'r') as f:
|
||||||
@@ -107,8 +96,6 @@ def get_status():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.warning(f"Konnte Statusdatei {filename} nicht lesen: {e}")
|
logging.warning(f"Konnte Statusdatei {filename} nicht lesen: {e}")
|
||||||
|
|
||||||
# Sortiere nach Startzeit, neuester Job zuerst
|
|
||||||
all_statuses.sort(key=lambda x: x.get('start_time', ''), reverse=True)
|
|
||||||
return jsonify(all_statuses)
|
return jsonify(all_statuses)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in New Issue
Block a user