AS4 Message Service Dokumentation

Der AS4 Message Service persistiert die Nachrichten und Bestätigungen, um eine spätere Nachverfolgbarkeit zu ermöglichen. Dieser Service erhält die AS4-Nachrichten und Bestätigungen über den Message-Broker und bietet über REST eine Abfragemöglichkeit an.

Features

Feature Property Default Beschreibung
Löschjob deletion.older-than (leer) Aktiviert die automatische Löschung alter Nachrichten (Zeitraum angeben)
Lösch-Intervall deletion.cron (leer) Cron-Ausdruck für den Löschjob
Lösch-Batch-Größe deletion.batch-size 100 Anzahl Nachrichten pro Lösch-Batch
Retry Lock retrySavingLock false Aktiviert den Retry-Mechanismus für das Speichern von Lock-Einträgen
Parallelität Business Messages businessMessageMaxConcurrency 50 Maximale Anzahl gleichzeitiger Verarbeitungsthreads für Business Messages
Parallelität Receipts receiptMaxConcurrency 50 Maximale Anzahl gleichzeitiger Verarbeitungsthreads für Receipts
Keycloak spring.profiles.active no-keycloak-enriched REST-API-Absicherung per OAuth2

Hardware Anforderungen

Eine Service-Instanz erfordert mindestens 512 MB RAM.

Wir empfehlen 0,4 CPU-Kerne je Instanz.

Logs werden auf die Festplatte geschrieben, entsprechend muss genügend Speicherplatz vorhanden sein.

Abhängigkeiten

Der Service greift auf einen Message-Broker zu, um Nachrichten zu empfangen und zu versenden.

Der Service greift auf eine SQL Datenbank zu, um Nachrichten zu speichern. Der Speicherverbrauch hängt vom Nachrichtenaufkommen sowie von der Archivierungs-/Löschstrategie ab.

Einfache Konfiguration der as4-message-service.properties

SQL Datenbank Anbindung

Der Einsatz des Microservice erfordert Zugriff auf eine SQL-Datenbank. Im Vorfeld muss ein Schema angelegt worden sein. Die Tabellen werden automatisch vom Microservice angelegt (via flyway).

Diese speziellen Datenbankparameter können je nach Bedarf verändert werden. Das Passwort wird als Environment Variable mit übergeben. Momentan werden die Datenbanksysteme MSSQL, Oracle und Postgresql unterstützt.

#=== JDBC Settings ==='
datasource.url=jdbc:postgresql://as4-database:5432/as4_messages
datasource.username=postgres
datasource.password=${DB_PASSWORD}
datasource.type=postgres
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

Im Fall einer Oracle-DB kann sich an den nachfolgenden Parametern orientiert werden.

datasource.url=jdbc:oracle:thin:@//as4-database-oracle:1521/orclas4
datasource.username=as4_messages
datasource.password=${DB_PASSWORD}
datasource.type=oracle

Es muss mindestens Oracle 12.2 eingesetzt werden, ältere Versionen werden nicht unterstützt.

Message Broker Anbindung

Die Kommunikation zwischen den verschiedenen AS4 Services erfolgt über einen Message-Broker.

#=== RabbitMQ Configuration ===#
rabbitmq.host=rabbitmq3
rabbitmq.port=5672
rabbitmq.username=guest
rabbitmq.password=guest

Der Service korreliert Business Message und das dazugehörige Receipt anhand der businessId. Genauer bedeutet es, dass auf die Ankunft beider Nachrichten gewartet wird. Dies passiert mit einem Eintrag der businessId als Key in der Datenbanktablle Lock, um eine Race Condition zu verhindern. Dieser Eintrag besteht nur bis die Verarbeitung und Persistierung der angekommenen Nachricht andauert. Wenn eine Nachricht ankommt, und bereits ein Lock-Eintrag für die vorhandene businessId besteht, wird die Nachricht nochmals eine kurze Zeit später konsumiert. In dieser Zeit sollte die Verarbeitung der verwandten Nachricht fertig und der dazu bestehende Lock-Eintrag gelöscht sein.

consumer.max.retries=3
#interval in ms (1000ms = 1s)
consumer.retry.interval=1000

Retry beim Speichern des Lock-Eintrags

Wenn eine Race Condition beim Speichern des Lock-Eintrags auftritt, kann der Service den Vorgang automatisch wiederholen. Default: false.

retrySavingLock=false

AMQP Routing Konfiguration

Im Standard-Routing ist keine weitere Konfiguration nötig. Die folgende Tabelle gibt eine Übersicht über alle vom Service genutzten Exchanges und ihre Gegenstellen. Die Default-Queue ergibt sich i.d.R. aus <exchange>.default (für as4.inbound und as4.receipt.outbound wird die Route/Queue je nach serviceId bestimmt).

Richtung Property Exchange Default-Queue Gegenstelle Zweck
Consumer businessMessageExchangeName as4.messages as4.messages.default AS4 Receipt Service & Outbound Sender Empfang der Business Message zur Persistierung
Consumer receiptExchangeName as4.receipt as4.receipt.default AS4 Receipt Service & Inbound Endpoint Empfang der Empfangsbestätigungen zur Persistierung
Producer inboundExchangeName as4.inbound je nach serviceId AS4 Address Service / B2B Message Service Weiterleitung der gespeicherten eingehenden Nachricht
Producer outboundExchangeName as4.receipt.outbound je nach serviceId B2B Message Service Weiterleitung der ausgehenden Empfangsbestätigung

Consumer-Gruppen anpassen

Für die Consumer-Exchanges kann die Gruppe geändert werden, falls Routing genutzt wird (ansonsten auf default belassen). Über max-concurrency lässt sich die Anzahl gleichzeitiger Verarbeitungsthreads pro Consumer einstellen (Default: 50).

businessMessageGroup=default
receiptGroup=default
businessMessageMaxConcurrency=50
receiptMaxConcurrency=50

Producer-Routing über RoutingKeyExpression

Im Gegensatz zu den anderen Microservices nutzt der AS4 Message Service für ausgehendes Routing eine RoutingKeyExpression (SpEL) statt eines fest gesetzten Headers. Im Default wird die Nachricht je nach serviceId an den AS4 Address Service oder B2B Message Service geroutet. Ein angepasstes Routing erfolgt über Header-Werte:

  • tenant: ILN Nummer des Senders
  • partner: ILN Nummer des Empfängers
  • sector: GAS, ELECTRICITY
  • serviceId: serviceId-Wert

Beispiel — Routing der eingehenden Nachricht nach serviceId:

inboundExchangeName=as4.inbound
inboundRoutingKeyExpression=headers.serviceId

Kombinierte Header-Routing-Keys sind möglich, z.B. nach Tenant und ServiceId:

outboundExchangeName=as4.receipt.outbound
outboundRoutingKeyExpression=headers.serviceId + '.' + headers.tenant

Löschjob

Um die alten Geschäftsnachrichten und Empfangsnachrichten aus der Datenbank zu entfernen, wurde ein Spring Quartz Scheduler integriert. Um den Scheduler zu aktivieren, muss die folgende Eigenschaft mit einem Wert versehen werden. Wenn kein Wert angegeben wird, wird der Planer nicht ausgelöst.

deletion.older-than=

Die Eigenschaft wird auch verwendet, um zu definieren, wie alt die zu löschenden Nachrichten im Vergleich zur aktuellen Datenzeit sein sollen. Von dieser Eigenschaft zugelassene Muster sind:

deletion.older-than=P1Y3M - 1 Jahr und 3 Monate (P ist nicht obligatorisch)
deletion.older-than=P1Y3M5D - 1 Jahr, 3 Monate und 5 Tage (P ist nicht obligatorisch)
deletion.older-than=P1Y3M5DT12H - 1 Jahr, 3 Monate, 5 Tage und 12 Stunden (T ist nicht zwingend erforderlich, um den Zeitteil zu identifizieren)
deletion.older-than=P1Y3M5DT12H30M40S - 1 Jahr, 3 Monate, 5 Tage und 12 Stunden 30 Minuten und 40 Sekunden (T ist nicht zwingend erforderlich, um den Zeitteil zu identifizieren)
deletion.older-than=T12H30M40S - 12 Stunden 30 Minuten und 40 Sekunden (T ist nicht zwingend erforderlich, um den Zeitteil zu identifizieren)

Konfiguration für die Quartz Scheduler-Datenbankverbindung und den Treiber, es gibt notwendigerweise nur die Konfiguration für die Datenbank, die verwendet wird, nicht alle davon.

Diese Property basiert auf RFC-3339.

#Postgres
datasource.driver=org.postgresql.Driver
datasource.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

#Oracle
datasource.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
datasource.driver=oracle.jdbc.driver.OracleDriver

#MySql
datasource.driverDelegateClass=org.quartz.impl.jdbcjobstore.MSSQLDelegate
datasource.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.quartz.properties.org.quartz.jobStore.selectWithLockSQL = SELECT * FROM {0}LOCKS WITH (UPDLOCK, ROWLOCK, HOLDLOCK)

Wenn Quartz Scheduler aktiviert ist, müssen auch die folgenden Eigenschaften festgelegt werden. Definiert das Intervall, in dem der Job ausgelöst wird. Beispiel eines Cron-Ausdrucks für Quartz Scheduler. Die Syntax für diesen Cron-Ausdruck unterscheidet sich von der normalen.

Sekunden: 0 – Der Job wird in der 0. Sekunde ausgeführt.
Minuten: 0 – Der Job wird in der 0. Minute ausgeführt.
Stunden: 12 – Der Job wird um 12:00 Uhr (Mittag) ausgeführt.
Tag des Monats: * – Der Job wird jeden Tag des Monats ausgeführt.
Monat: * – Der Job wird jeden Monat ausgeführt.
Wochentag: ? - Es ist kein bestimmter Wochentag erforderlich (es spielt keine Rolle).
	
deletion.cron=0 33 * * * ? - jede Stunde bei Minute 33
deletion.cron=0 */33 * * * ? - alle 33 Minuten

Der Löschjob selektiert zuerst Nachrichten mit den konfigurierten Filtern und löscht diese dann in einzelnen Delete-Statements. Es gibt eine weitere Property deletion.batch-size, mit der man die Anzahl der selektierten Nachrichten pro Batch steuern kann.

deletion.batch-size=100

Der default Wert ist 100.

Zeitzone

Es wird empfohlen, die Server-Zeitzone auf die gewünschte Zeitzone einzustellen. Alle Server müssen die gleiche Zeitzone nutzen. Die Server-Zeitzone darf nachträglich nicht mehr geändert werden.

REST API Dokumentation

Die API bietet die Möglichkeit zur Abfrage von verarbeiteten AS4 Nachrichten und zugehörigen Quittungen.

Darüber hinaus bietet die API Server-Health Informationen an.

Ein KontextPath Präfix kann über folgende Property konfiguriert werden: server.servlet.contextPath.

Der Port lässt sich über folgende Property konfigurieren: server.port=8080.

Swagger

Die Beschreibung der REST API lässt sich, im Fall einer Docker Installation, unter

http://host.docker.internal:8086/aep-as4-message-service/swagger-ui/index.html#/

oder unter

http://localhost:8080/aep-as4-message-service/swagger-ui/index.html#/

finden.

Keycloak

Bei Bedarf kann die REST-API per Keycloak abgesichert werden.

In Keycloak können die Mandanten, auf die der User Zugriff hat, eingeschränkt werden. Weitere Details entnehmen Sie der Doku.

Upgrade zur Version 2024-03-xx

Mit dieser Version wird die Datenbank selbstständig aktualisiert.

Es kann sein, dass eine manuelle Datenbereinigung nötig wird: falls Sie zuvor manuell Testdaten abseits der üblichen Workflows eingespielt haben (z.B. direkt in die Datenbank oder via Messaging an den internen Queues), können diese Daten möglicherweise das Update verhindern, wenn sie das neu eingeführte Unique-Constraint (Tabelle receipt, Spalte business_id) verletzen. In diesem Fall müssen Sie die Daten manuell bereinigen. Testdaten dieser Art werden, wenn überhaupt dann nur in Entwicklungsumgebungen eingespielt.

In jedem Fall empfehlen wir Ihnen, vor der Bereinigung die neue Version auszuführen. Denn das Datenbank-Update beinhaltet auch die Erzeugung von Indexen, die auch die Performance der Bereinigung verbessern.

Die Bereinigung erfolgt, indem unzulässige Duplikate gelöscht werden. Sie können die Datenbank mithilfe des folgenden (Postgres) SQL-Scripts bereinigen:

WITH cte AS (
    SELECT business_id, MIN(as4_id) as as4_id
    FROM receipt
    GROUP BY business_id
    HAVING COUNT(business_id) > 1
)
DELETE FROM receipt
WHERE business_id IN (SELECT business_id FROM cte)
  AND as4_id NOT IN (SELECT as4_id FROM cte);

Erneute Verarbeitung von AS4-Nachrichten

Um Nachrichten erneut zu verarbeiten, werden AS4-Nachrichten mithilfe eines Filters aus der Datenbank des AS4-Message-Services abgerufen und dann erneut an die entsprechenden Services übermittelt. Mehr Infos gibt es in der folgenden Dokumentation: AS4-Redelivery

Anhang: Gesamtkonfiguration

Folgende Konfiguration reicht in einem Standard-System aus: application.properties:

#=== JDBC Settings ==='
datasource.url=jdbc:postgresql://as4-database:5432/as4_messages?currentSchema=as4_messages
datasource.username=postgres
datasource.password=${DB_PASSWORD}
datasource.type=postgres

#=== RabbitMQ Configuration ===#
rabbitmq.host=rabbitmq3
rabbitmq.port=5672
rabbitmq.username=guest
rabbitmq.password=${RABBITMQ_PASSWORD}

Allgemeine Hinweise zur Konfiguration finden Sie hier.

View Me   Edit Me