Files
Dokumenten-Check/Scripts/DC_BACKEND_PKG.sql
Wolf G. Beckmann 1816168d1f initial commit
2026-04-27 14:57:33 +02:00

298 lines
10 KiB
MySQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================================
-- DC_BACKEND_PKG
-- PL/SQL-Schnittstelle zum Quarkus dc-backend (Kubernetes Service dc-backend:8090)
--
-- Voraussetzungen:
-- - APEX_WEB_SERVICE-Berechtigung für das Schema:
-- GRANT EXECUTE ON APEX_240100.APEX_WEB_SERVICE TO <schema>; -- APEX-Version anpassen
-- - ACL für ausgehende HTTP-Verbindung im selben Namespace:
-- DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
-- host => 'dc-backend', lower_port => 8090, upper_port => 8090,
-- ace => xs$ace_type(privilege_list => xs$name_list('connect','resolve'),
-- principal_name => '<schema>', principal_type => xs_acl.ptype_db));
--
-- Deployment:
-- sqlplus user/pass@db @"Scripts/DC_BACKEND_PKG.sql"
-- =============================================================================
-- =============================================================================
-- Package Spec
-- =============================================================================
CREATE OR REPLACE PACKAGE DC_BACKEND_PKG AS
-- Basis-URL des dc-backend Kubernetes Service
c_base_url CONSTANT VARCHAR2(200) := 'http://dc-backend:8090';
-- API-Key (X-API-KEY Header).
-- Leer = kein Auth (Dev-Modus).
-- Zur Laufzeit setzen: DC_BACKEND_PKG.g_api_key := 'mein-key';
g_api_key VARCHAR2(500) := '';
-- -------------------------------------------------------------------------
-- Startet die KI-gestützte Dokumentenprüfung für ein Projekt (asynchron).
-- Das Projekt muss im Status PENDING sein.
-- POST /check/{p_project_id} → 202 Accepted
--
-- p_project_id ID des dc_projects-Eintrags
-- p_status_code HTTP-Statuscode der Antwort (202 = OK, 409 = nicht PENDING)
-- p_response JSON-Antwort des Backend
-- -------------------------------------------------------------------------
PROCEDURE start_check(
p_project_id IN NUMBER,
p_status_code OUT NUMBER,
p_response OUT VARCHAR2
);
-- -------------------------------------------------------------------------
-- Health-Check: prüft ob der dc-backend Service erreichbar ist.
-- GET /check/health → 200 UP
--
-- Rückgabe: TRUE = Service läuft, FALSE = nicht erreichbar
-- -------------------------------------------------------------------------
FUNCTION health_check RETURN BOOLEAN;
-- -------------------------------------------------------------------------
-- Startet die Prüfung und wirft eine Exception wenn nicht 202 zurückkommt.
-- Convenience-Wrapper für direkte APEX-Button-Aufrufe.
-- -------------------------------------------------------------------------
PROCEDURE start_check_or_raise(
p_project_id IN NUMBER
);
-- -------------------------------------------------------------------------
-- Fortschritts-Record
-- -------------------------------------------------------------------------
TYPE t_project_status IS RECORD (
status dc_projects.status%TYPE,
processing_progress dc_projects.progress%TYPE,
is_completed BOOLEAN,
is_running BOOLEAN,
is_pending BOOLEAN
);
-- -------------------------------------------------------------------------
-- Liest Status und Fortschritt eines Projekts direkt aus der DB.
-- Kein REST-Aufruf sofort und transaktionssicher.
--
-- Beispiel:
-- l_s := DC_BACKEND_PKG.get_status(1);
-- DBMS_OUTPUT.PUT_LINE(l_s.status || ' ' || l_s.processing_progress || '%');
-- -------------------------------------------------------------------------
FUNCTION get_status(
p_project_id IN NUMBER
) RETURN t_project_status;
-- -------------------------------------------------------------------------
-- Wartet (polling) bis das Projekt COMPLETED oder ein Timeout erreicht ist.
-- Wirft eine Exception bei Timeout oder wenn das Projekt nicht gefunden wird.
--
-- p_timeout_sec Max. Wartezeit in Sekunden (Default: 1800 = 30 Min.)
-- p_interval_sec Polling-Intervall in Sekunden (Default: 5)
-- -------------------------------------------------------------------------
PROCEDURE wait_for_completion(
p_project_id IN NUMBER,
p_timeout_sec IN NUMBER DEFAULT 1800,
p_interval_sec IN NUMBER DEFAULT 5
);
END DC_BACKEND_PKG;
/
-- =============================================================================
-- Package Body
-- =============================================================================
CREATE OR REPLACE PACKAGE BODY DC_BACKEND_PKG AS
-- -------------------------------------------------------------------------
-- Setzt gemeinsame Request-Header (Content-Type + optional API-Key)
-- -------------------------------------------------------------------------
PROCEDURE set_headers IS
l_idx PLS_INTEGER := 1;
BEGIN
APEX_WEB_SERVICE.G_REQUEST_HEADERS.DELETE;
APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).NAME := 'Content-Type';
APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).VALUE := 'application/json';
l_idx := l_idx + 1;
IF g_api_key IS NOT NULL AND LENGTH(TRIM(g_api_key)) > 0 THEN
APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).NAME := 'X-API-KEY';
APEX_WEB_SERVICE.G_REQUEST_HEADERS(l_idx).VALUE := g_api_key;
END IF;
END set_headers;
-- -------------------------------------------------------------------------
PROCEDURE start_check(
p_project_id IN NUMBER,
p_status_code OUT NUMBER,
p_response OUT VARCHAR2
) IS
l_url VARCHAR2(500);
l_response CLOB;
BEGIN
l_url := c_base_url || '/check/' || TO_CHAR(p_project_id);
set_headers();
l_response := APEX_WEB_SERVICE.MAKE_REST_REQUEST(
p_url => l_url,
p_http_method => 'POST',
p_body => '{}' -- leerer Body, projectId ist im Pfad
);
p_status_code := APEX_WEB_SERVICE.G_STATUS_CODE;
p_response := SUBSTR(l_response, 1, 4000);
EXCEPTION
WHEN OTHERS THEN
p_status_code := -1;
p_response := 'Verbindungsfehler: ' || SQLERRM;
END start_check;
-- -------------------------------------------------------------------------
FUNCTION health_check RETURN BOOLEAN IS
l_url VARCHAR2(500);
l_response CLOB;
l_status NUMBER;
BEGIN
l_url := c_base_url || '/check/health';
set_headers();
l_response := APEX_WEB_SERVICE.MAKE_REST_REQUEST(
p_url => l_url,
p_http_method => 'GET'
);
l_status := APEX_WEB_SERVICE.G_STATUS_CODE;
RETURN l_status = 200;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END health_check;
-- -------------------------------------------------------------------------
PROCEDURE start_check_or_raise(
p_project_id IN NUMBER
) IS
l_status NUMBER;
l_response VARCHAR2(4000);
BEGIN
start_check(
p_project_id => p_project_id,
p_status_code => l_status,
p_response => l_response
);
IF l_status = 202 THEN
-- OK: Verarbeitung wurde gestartet
NULL;
ELSIF l_status = 409 THEN
RAISE_APPLICATION_ERROR(-20100,
'Projekt ' || p_project_id || ' ist nicht im Status PENDING.');
ELSIF l_status = 401 THEN
RAISE_APPLICATION_ERROR(-20101,
'Ungültiger API-Key für dc-backend.');
ELSIF l_status = -1 THEN
RAISE_APPLICATION_ERROR(-20102,
'dc-backend nicht erreichbar: ' || l_response);
ELSE
RAISE_APPLICATION_ERROR(-20103,
'Unerwarteter HTTP-Status ' || l_status || ': ' || l_response);
END IF;
END start_check_or_raise;
-- -------------------------------------------------------------------------
FUNCTION get_status(
p_project_id IN NUMBER
) RETURN t_project_status IS
l_rec t_project_status;
BEGIN
SELECT status, progress
INTO l_rec.status, l_rec.processing_progress
FROM dc_projects
WHERE id = p_project_id;
l_rec.is_completed := l_rec.status = 'COMPLETED';
l_rec.is_running := l_rec.status = 'IN_PROGRESS';
l_rec.is_pending := l_rec.status = 'PENDING';
RETURN l_rec;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20110,
'Projekt ' || p_project_id || ' nicht gefunden.');
END get_status;
-- -------------------------------------------------------------------------
PROCEDURE wait_for_completion(
p_project_id IN NUMBER,
p_timeout_sec IN NUMBER DEFAULT 1800,
p_interval_sec IN NUMBER DEFAULT 5
) IS
l_start TIMESTAMP := SYSTIMESTAMP;
l_status t_project_status;
BEGIN
LOOP
l_status := get_status(p_project_id);
EXIT WHEN l_status.is_completed;
IF EXTRACT(SECOND FROM (SYSTIMESTAMP - l_start))
+ EXTRACT(MINUTE FROM (SYSTIMESTAMP - l_start)) * 60
+ EXTRACT(HOUR FROM (SYSTIMESTAMP - l_start)) * 3600
> p_timeout_sec
THEN
RAISE_APPLICATION_ERROR(-20111,
'Timeout nach ' || p_timeout_sec || 's Projekt ' ||
p_project_id || ' noch im Status ' || l_status.status ||
' (' || l_status.processing_progress || '%).');
END IF;
DBMS_SESSION.SLEEP(p_interval_sec);
END LOOP;
END wait_for_completion;
END DC_BACKEND_PKG;
/
-- =============================================================================
-- Schnelltest (optional, auskommentiert)
-- =============================================================================
/*
-- Health-Check
BEGIN
IF DC_BACKEND_PKG.health_check() THEN
DBMS_OUTPUT.PUT_LINE('dc-backend: UP');
ELSE
DBMS_OUTPUT.PUT_LINE('dc-backend: NICHT ERREICHBAR');
END IF;
END;
/
-- Prüfung starten (Projekt-ID anpassen)
DECLARE
l_status NUMBER;
l_response VARCHAR2(4000);
BEGIN
DC_BACKEND_PKG.start_check(
p_project_id => 1,
p_status_code => l_status,
p_response => l_response
);
DBMS_OUTPUT.PUT_LINE('Status: ' || l_status);
DBMS_OUTPUT.PUT_LINE('Response: ' || l_response);
END;
/
*/