SAP Event Mesh ermöglicht lose gekoppelte, event-basierte Kommunikation zwischen ABAP-Systemen und anderen Anwendungen auf der SAP Business Technology Platform. Mit RAP Business Events kannst du Geschäftsereignisse definieren und in Echtzeit an externe Systeme propagieren.
Was ist Event-driven Architecture?
Event-driven Architecture (EDA) ist ein Architekturmuster, bei dem Systeme über Events kommunizieren statt über direkte API-Aufrufe:
| Aspekt | Direkte Integration | Event-driven |
|---|---|---|
| Kopplung | Eng (synchron) | Lose (asynchron) |
| Verfügbarkeit | Abhängig vom Zielsystem | Unabhängig |
| Skalierbarkeit | Limitiert | Hoch |
| Fehlertoleranz | Niedrig | Hoch (Retry/Replay) |
| Latenz | Synchron | Asynchron |
| Use Cases | Transaktionale Konsistenz | Benachrichtigungen, Replikation |
SAP Event Mesh Konzept
SAP Event Mesh ist ein vollständig verwalteter Messaging-Service auf der BTP:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐│ ABAP Cloud │ │ SAP Event Mesh │ │ Subscriber ││ (Publisher) │─────>│ (Message Broker)│─────>│ (Consumer) ││ │ │ │ │ ││ RAP Business │ │ - Queues │ │ - ABAP Cloud ││ Events │ │ - Topics │ │ - CAP App ││ │ │ - Subscriptions │ │ - 3rd Party │└─────────────────┘ └──────────────────┘ └─────────────────┘Kernkonzepte:
- Event: Nachricht über ein Geschäftsereignis (z.B. “Auftrag erstellt”)
- Topic: Logischer Kanal für Events (z.B. “sap/sales/order/created”)
- Queue: Persistenter Speicher für Events pro Subscriber
- Subscription: Verbindung zwischen Topic und Queue
RAP Business Event definieren
Business Events werden in der Behavior Definition deklariert und bei Zustandsänderungen ausgelöst.
Behavior Definition mit Events
managed implementation in class zbp_i_salesorder unique;strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrderpersistent table zsalesorderlock masterauthorization master ( instance )etag master LastChangedAtwith additional save{ create; update; delete;
// Business Events definieren event created; event updated; event deleted; event statusChanged parameter ZA_StatusChangeInfo;}Event mit Parameter-Struktur
Für komplexe Events definierst du eine Abstract Entity als Parameter:
@EndUserText.label: 'Status Change Info'define abstract entity ZA_StatusChangeInfo{ SalesOrderId : abap.char(10); OldStatus : abap.char(2); NewStatus : abap.char(2); ChangedBy : abap.uname; ChangedAt : timestampl;}Event Publishing
Events werden in der Behavior Implementation ausgelöst – typischerweise in Determinations oder Actions.
Event bei Create auslösen
CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS raise_created_event FOR DETERMINE ON SAVE IMPORTING keys FOR SalesOrder~raiseCreatedEvent.ENDCLASS.
CLASS lhc_salesorder IMPLEMENTATION. METHOD raise_created_event. " Event für neue Instanzen auslösen RAISE ENTITY EVENT zi_salesorder~created FROM VALUE #( FOR key IN keys ( %key = key-%key ) ). ENDMETHOD.ENDCLASS.Event bei Statusänderung mit Parametern
CLASS lhc_salesorder DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS on_status_change FOR DETERMINE ON SAVE IMPORTING keys FOR SalesOrder~onStatusChange.ENDCLASS.
CLASS lhc_salesorder IMPLEMENTATION. METHOD on_status_change. " Alte und neue Werte lesen READ ENTITIES OF zi_salesorder IN LOCAL MODE ENTITY SalesOrder ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(orders).
" Event mit Parametern auslösen RAISE ENTITY EVENT zi_salesorder~statusChanged FROM VALUE #( FOR order IN orders ( %key = order-%key %param = VALUE #( salesorderid = order-SalesOrderId oldstatus = order-OldStatus newstatus = order-Status changedby = sy-uname changedat = utclong_current( ) ) ) ). ENDMETHOD.ENDCLASS.Determination für Event-Trigger
managed implementation in class zbp_i_salesorder unique;strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrderpersistent table zsalesorderlock masterauthorization master ( instance )with additional save{ create; update; delete;
// Events event created; event statusChanged parameter ZA_StatusChangeInfo;
// Determinations für Event-Trigger determination raiseCreatedEvent on save { create; } determination onStatusChange on save { field Status; }}Event Consumption
Events können in anderen ABAP-Systemen oder externen Anwendungen konsumiert werden.
Event Handler in ABAP Cloud
CLASS zcl_salesorder_event_handler DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_rap_event_handler.ENDCLASS.
CLASS zcl_salesorder_event_handler IMPLEMENTATION. METHOD if_rap_event_handler~handle. " Event-Typ prüfen CASE io_event->get_event_name( ). WHEN 'CREATED'. handle_created( io_event ). WHEN 'STATUSCHANGED'. handle_status_changed( io_event ). ENDCASE. ENDMETHOD.
METHOD handle_created. DATA: lt_keys TYPE TABLE OF zi_salesorder.
" Event-Daten lesen io_event->get_business_data( IMPORTING et_business_data = lt_keys ).
" Verarbeitung: z.B. Nachricht senden, Log schreiben LOOP AT lt_keys INTO DATA(ls_key). " Business-Logik ENDLOOP. ENDMETHOD.
METHOD handle_status_changed. DATA: lt_params TYPE TABLE OF za_statuschangeinfo.
" Parameter-Daten lesen io_event->get_business_data( IMPORTING et_business_data = lt_params ).
LOOP AT lt_params INTO DATA(ls_param). " Z.B. E-Mail senden bei Statuswechsel IF ls_param-newstatus = 'AP'. " Approved send_approval_notification( ls_param ). ENDIF. ENDLOOP. ENDMETHOD.ENDCLASS.Event Handler registrieren
Die Registrierung erfolgt über das Business Event Handling Framework:
" Registrierung in Customizing-Tabelle oder per APIDATA(lo_registration) = cl_beh_event_registration=>get_instance( ).
lo_registration->register_handler( iv_event_name = 'CREATED' iv_handler_class = 'ZCL_SALESORDER_EVENT_HANDLER' iv_source_entity = 'ZI_SALESORDER' ).Konfiguration im BTP Cockpit
1. Event Mesh Service erstellen
- Im BTP Cockpit navigiere zu deinem Subaccount
- Gehe zu Service Marketplace → SAP Event Mesh
- Erstelle eine Service-Instanz mit Plan
default - Erstelle einen Service Key für die Authentifizierung
2. Message Client konfigurieren
Die Service-Key-Daten enthalten alle notwendigen Verbindungsparameter:
{ "management": [ { "oa2": { "clientid": "sb-event-mesh-client!...", "clientsecret": "...", "tokenendpoint": "https://.../oauth/token" }, "uri": "https://enterprise-messaging-hub-backend..." } ], "messaging": [ { "oa2": { "clientid": "...", "clientsecret": "...", "tokenendpoint": "..." }, "protocol": ["amqp10ws"], "broker": { "type": "sapmgw" }, "uri": "wss://enterprise-messaging-pubsub.cfapps..." } ], "namespace": "default/sap.s4/salesorder"}3. Communication Arrangement im ABAP-System
┌──────────────────────────────────────────────────────────────┐│ Communication Arrangement │├──────────────────────────────────────────────────────────────┤│ Scenario: SAP_COM_0092 (Enterprise Eventing Integration) ││ ││ Communication System: EVENT_MESH_SYSTEM ││ ├── Host: enterprise-messaging-pubsub.cfapps... ││ ├── Port: 443 ││ └── Auth: OAuth 2.0 Client Credentials ││ ││ Outbound Services: ││ └── Enterprise Event Enablement: Active │└──────────────────────────────────────────────────────────────┘4. Channel konfigurieren
Im ABAP-System unter Enterprise Event Enablement:
" Event Channel anlegenDATA(lo_channel) = cl_eee_channel_factory=>create_channel( iv_channel_id = 'Z_SALESORDER_EVENTS' iv_description = 'Sales Order Events' iv_topic_space = 'default/sap.s4/salesorder' iv_destination = 'EVENT_MESH_DESTINATION' ).
" Topic-Bindinglo_channel->add_topic_binding( iv_event_type = 'ZI_SALESORDER.CREATED' iv_topic = 'sap/salesorder/created/v1' ).
lo_channel->add_topic_binding( iv_event_type = 'ZI_SALESORDER.STATUSCHANGED' iv_topic = 'sap/salesorder/statuschanged/v1' ).Event Consumption in externen Systemen
CAP Application (Node.js)
const cds = require('@sap/cds');
module.exports = async (srv) => { // Event Mesh Verbindung const messaging = await cds.connect.to('messaging');
// Event-Handler registrieren messaging.on('sap/salesorder/created/v1', async (msg) => { const { SalesOrderId } = msg.data; console.log(`New sales order created: ${SalesOrderId}`);
// Business-Logik await processSalesOrder(SalesOrderId); });
messaging.on('sap/salesorder/statuschanged/v1', async (msg) => { const { SalesOrderId, OldStatus, NewStatus } = msg.data; console.log(`Status changed: ${SalesOrderId} from ${OldStatus} to ${NewStatus}`); });};Python Consumer
from sap_event_mesh_client import EventMeshClient
# Client initialisierenclient = EventMeshClient( service_key_path='event-mesh-service-key.json')
# Queue abonnieren@client.subscribe('queue:salesorder-events')def handle_salesorder_event(message): event_type = message.headers.get('type')
if event_type == 'sap/salesorder/created/v1': order_id = message.body['SalesOrderId'] print(f'Processing new order: {order_id}') # Business-Logik
message.ack() # Nachricht bestätigen
# Consumer startenclient.start()Komplettes Beispiel: Order Processing Pipeline
Business Object mit Events
managed implementation in class zbp_i_purchaseorder unique;strict ( 2 );
define behavior for ZI_PurchaseOrder alias PurchaseOrderpersistent table zpurchaseorderlock masterauthorization master ( instance )etag master LastChangedAtwith additional save{ create; update; delete;
// Aktionen action ( features : instance ) approve result [1] $self; action ( features : instance ) reject result [1] $self;
// Events für jede wichtige Zustandsänderung event created; event approved parameter ZA_ApprovalInfo; event rejected parameter ZA_RejectionInfo; event amountChanged parameter ZA_AmountChangeInfo;
// Trigger determination triggerCreated on save { create; } determination triggerAmountChange on save { field TotalAmount; }}Event-Parameter
@EndUserText.label: 'Approval Info'define abstract entity ZA_ApprovalInfo{ PurchaseOrderId : abap.char(10); ApprovedBy : abap.uname; ApprovedAt : timestampl; TotalAmount : abap.dec(15,2);}
@EndUserText.label: 'Rejection Info'define abstract entity ZA_RejectionInfo{ PurchaseOrderId : abap.char(10); RejectedBy : abap.uname; RejectedAt : timestampl; RejectionReason : abap.char(255);}Action Implementation mit Event
CLASS lhc_purchaseorder IMPLEMENTATION. METHOD approve. " Status aktualisieren MODIFY ENTITIES OF zi_purchaseorder IN LOCAL MODE ENTITY PurchaseOrder UPDATE FIELDS ( Status ApprovedBy ApprovedAt ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky Status = 'AP' ApprovedBy = sy-uname ApprovedAt = utclong_current( ) ) ) FAILED failed REPORTED reported.
" Ergebnis lesen READ ENTITIES OF zi_purchaseorder IN LOCAL MODE ENTITY PurchaseOrder ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(orders).
" Event auslösen RAISE ENTITY EVENT zi_purchaseorder~approved FROM VALUE #( FOR order IN orders ( %key = order-%key %param = VALUE #( purchaseorderid = order-PurchaseOrderId approvedby = order-ApprovedBy approvedat = order-ApprovedAt totalamount = order-TotalAmount ) ) ).
" Result zurückgeben result = VALUE #( FOR order IN orders ( %tky = order-%tky %param = order ) ). ENDMETHOD.ENDCLASS.Best Practices
| Thema | Empfehlung |
|---|---|
| Event-Granularität | Ein Event pro Geschäftsereignis, nicht zu feingranular |
| Idempotenz | Consumer müssen doppelte Events verarbeiten können |
| Event-Schema | Versionierung beachten (v1, v2), Breaking Changes vermeiden |
| Parameter | Nur notwendige Daten im Event, nicht gesamte Entität |
| Error Handling | Dead-Letter-Queue für fehlgeschlagene Events konfigurieren |
| Monitoring | SAP Event Mesh Dashboard für Metriken nutzen |
| Testing | Lokale Events testen vor Produktiv-Integration |
| Security | Separate Service Keys für Entwicklung und Produktion |
Weiterführende Themen
- RAP Actions und Functions - Aktionen, die Events auslösen
- Destination Service - Externe Systeme anbinden
- RAP Basics - Grundlagen der RAP-Entwicklung