feat: Nextcloud Talk Error Handler als failure_module
Bei jedem Flow-Fehler: Talk-Nachricht mit Step und Fehlermeldung. Markiert laufenden DB-Job als failed und gibt Server frei. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -125,6 +125,21 @@ value:
|
||||
lock: '!inline
|
||||
webhook_verarbeiten_&_naechsten_restore_auf_demselben_server_starten.lock'
|
||||
language: python3
|
||||
failure_module:
|
||||
id: failure
|
||||
summary: Flow-Fehler per Nextcloud Talk melden
|
||||
value:
|
||||
type: rawscript
|
||||
content: '!inline flow_fehler_handler.py'
|
||||
input_transforms:
|
||||
error:
|
||||
type: javascript
|
||||
expr: error
|
||||
flow_input:
|
||||
type: javascript
|
||||
expr: flow_input
|
||||
lock: '!inline flow_fehler_handler.lock'
|
||||
language: python3
|
||||
schema:
|
||||
$schema: https://json-schema.org/draft/2020-12/schema
|
||||
type: object
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# py: 3.12
|
||||
anyio==4.12.1
|
||||
bcrypt==5.0.0
|
||||
certifi==2026.2.25
|
||||
cffi==2.0.0
|
||||
cryptography==46.0.5
|
||||
h11==0.16.0
|
||||
httpcore==1.0.9
|
||||
httpx==0.28.1
|
||||
idna==3.11
|
||||
invoke==2.2.1
|
||||
mysql-connector-python==9.6.0
|
||||
paramiko==4.0.0
|
||||
pycparser==3.0
|
||||
pynacl==1.6.2
|
||||
typing-extensions==4.15.0
|
||||
wmill==1.657.2
|
||||
@@ -0,0 +1,75 @@
|
||||
import wmill, base64, httpx, json, mysql.connector
|
||||
|
||||
def _send_talk(message: str):
|
||||
try:
|
||||
nc_url = wmill.get_variable("f/Backup/nextcloud_talk_url").rstrip("/")
|
||||
nc_room = wmill.get_variable("f/Backup/nextcloud_talk_room")
|
||||
nc_user = wmill.get_variable("f/Backup/nextcloud_talk_user")
|
||||
nc_password = wmill.get_variable("f/Backup/nextcloud_talk_password")
|
||||
credentials = base64.b64encode(f"{nc_user}:{nc_password}".encode()).decode()
|
||||
httpx.post(
|
||||
f"{nc_url}/ocs/v2.php/apps/spreed/api/v1/chat/{nc_room}",
|
||||
headers={
|
||||
"Authorization": f"Basic {credentials}",
|
||||
"OCS-APIREQUEST": "true",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
json={"message": message},
|
||||
timeout=15,
|
||||
verify=False,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Talk-Fehler (nicht kritisch): {e}")
|
||||
|
||||
def main(error: dict, flow_input: dict = {}):
|
||||
msg = error.get("message", "Unbekannter Fehler")
|
||||
name = error.get("name", "")
|
||||
step_id = error.get("step_id", "")
|
||||
|
||||
# Laufenden Job in DB als failed markieren und Server freigeben
|
||||
try:
|
||||
db_cfg = json.loads(wmill.get_variable("f/Backup/mysql_config"))
|
||||
conn = mysql.connector.connect(**db_cfg)
|
||||
cur = conn.cursor(dictionary=True)
|
||||
|
||||
cur.execute("""
|
||||
SELECT job_uuid FROM Kunden.`bronze.restore.jobs`
|
||||
WHERE status = 'running'
|
||||
LIMIT 1
|
||||
""")
|
||||
row = cur.fetchone()
|
||||
if row:
|
||||
job_uuid = row["job_uuid"]
|
||||
cur.execute("""
|
||||
UPDATE Kunden.`bronze.restore.jobs`
|
||||
SET status = 'failed', finished_at = NOW()
|
||||
WHERE job_uuid = %s
|
||||
""", (job_uuid,))
|
||||
cur.execute("""
|
||||
UPDATE Kunden.`bronze.restore.server`
|
||||
SET current_job_uuid = NULL
|
||||
WHERE current_job_uuid = %s
|
||||
""", (job_uuid,))
|
||||
cur.execute("""
|
||||
DELETE FROM Kunden.`bronze.restore.session`
|
||||
WHERE job_uuid = %s
|
||||
""", (job_uuid,))
|
||||
conn.commit()
|
||||
print(f"DB: Job {job_uuid} als failed markiert, Server freigegeben.")
|
||||
|
||||
cur.close(); conn.close()
|
||||
except Exception as e:
|
||||
print(f"DB-Cleanup fehlgeschlagen (nicht kritisch): {e}")
|
||||
|
||||
step_line = f"\nStep: `{step_id}`" if step_id else ""
|
||||
type_line = f"\nTyp: {name}" if name else ""
|
||||
talk_msg = (
|
||||
f"🚨 **Backup Restore Flow Fehler**{step_line}\n"
|
||||
f"Fehler: {msg[:300]}"
|
||||
f"{type_line}"
|
||||
)
|
||||
|
||||
_send_talk(talk_msg)
|
||||
print(f"Talk-Nachricht gesendet:\n{talk_msg}")
|
||||
return {"notified": True}
|
||||
Reference in New Issue
Block a user