RAP Business Events: Event-driven Architecture mit ABAP Cloud

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Business Events in RAP ermöglichen event-driven Architecture: Statt direkter Methodenaufrufe kommunizieren Komponenten über Events. Das entkoppelt Systeme, ermöglicht asynchrone Verarbeitung und macht Architekturen skalierbarer und wartbarer.

Das Problem: Tight Coupling

Ohne Events (Tight Coupling)

" ❌ Direkte Abhängigkeit: Travel → Email → Logging
METHOD approve_travel.
" 1. Status ändern
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( ( %tky = ls_travel-%tky Status = 'A' ) ).
" 2. Email senden (direkte Abhängigkeit!)
TRY.
cl_email_sender=>send(
recipient = ls_travel-customer_email
subject = 'Travel approved'
).
CATCH cx_email_error.
" Was tun bei Fehler?
ENDTRY.
" 3. Loggen (direkte Abhängigkeit!)
cl_logger=>log( |Travel { ls_travel-TravelId } approved| ).
" 4. Analytics updaten (direkte Abhängigkeit!)
zcl_analytics=>track_approval( ls_travel-TravelId ).
" 5. External System benachrichtigen (direkte Abhängigkeit!)
zcl_external_api=>notify_approval( ls_travel ).
ENDMETHOD.

Probleme:

  • 🔴 Tight Coupling: Approval-Logik kennt alle Consumers
  • 🔴 Synchron: Alle Schritte blockieren Hauptprozess
  • 🔴 Nicht erweiterbar: Neuer Consumer = Code ändern
  • 🔴 Fehleranfällig: Ein fehlgeschlagener Consumer bricht alles ab
  • 🔴 Langsam: Email + API + Logging = 2-3 Sekunden

Mit Events (Loose Coupling)

" ✅ Event-driven: Travel → Event → Consumers (entkoppelt)
METHOD approve_travel.
" 1. Status ändern
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( ( %tky = ls_travel-%tky Status = 'A' ) ).
" 2. Event auslösen (Fire & Forget)
RAISE ENTITY EVENT zi_travel~TravelApproved
FROM VALUE #( ( %key-TravelId = ls_travel-TravelId
%param-ApprovedBy = sy-uname
%param-ApprovedAt = sy-datum ) ).
" Fertig! Consumers reagieren asynchron
ENDMETHOD.

Vorteile:

  • Loose Coupling: Approval-Logik kennt keine Consumers
  • Asynchron: Consumers verarbeiten parallel
  • Erweiterbar: Neue Consumers ohne Code-Änderung
  • Resilient: Consumer-Fehler beeinflussen Hauptprozess nicht
  • Schnell: Hauptprozess läuft sofort weiter (< 100ms)

Event Anatomy

┌─────────────────────────────────────────────────────┐
│ Event Publisher │
│ (RAP Business Object) │
│ │
│ METHOD approve_travel. │
│ RAISE ENTITY EVENT zi_travel~TravelApproved ... │
│ ENDMETHOD. │
└────────────────┬────────────────────────────────────┘
│ Event: TravelApproved
│ Payload: { TravelId, ApprovedBy, ApprovedAt }
┌─────────────────────────────────────────────────────┐
│ Event Infrastructure │
│ (RAP Framework / Event Mesh) │
└────────┬────────────────────────────────┬──────────┘
│ │
▼ ▼
┌────────────────────┐ ┌────────────────────────┐
│ Consumer 1 │ │ Consumer 2 │
│ (Email) │ │ (Analytics) │
│ │ │ │
│ on_event( ). │ │ on_event( ). │
│ send_email( ) │ │ track_approval( ) │
└────────────────────┘ └────────────────────────┘
┌────────────────────┐
│ Consumer 3 │
│ (External API) │
│ │
│ on_event( ). │
│ notify_system( ) │
└────────────────────┘

Event Definition in BDEF

Einfaches Event

define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
{
create;
update;
delete;
// Event Definition
event TravelApproved;
// Action die Event auslöst
action approve result [1] $self;
}

Event mit Parametern

define behavior for ZI_Travel alias Travel
{
// Event mit Parameter-Struktur
event TravelApproved parameter ZA_TravelApprovedParam;
action approve result [1] $self;
}

Parameter-Struktur (Abstract Entity):

@EndUserText.label: 'Travel Approved Event Parameters'
define abstract entity ZA_TravelApprovedParam
{
TravelId : /dmo/travel_id;
ApprovedBy : syuname;
ApprovedAt : sydatum;
ApprovalNote : abap.string(255);
}

Event mit Standard-Parameter

define behavior for ZI_Travel alias Travel
{
// Event mit vordefiniertem %param
event TravelApproved parameter ZA_TravelApprovedParam;
// Oder: Nur Key-Felder (kein expliziter Parameter)
event TravelCancelled;
}

Event Raising (Publisher)

Event in Action auslösen

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS approve FOR MODIFY
IMPORTING keys FOR ACTION Travel~approve RESULT result.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD approve.
" 1. Daten lesen
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel)
FAILED failed
REPORTED reported.
" 2. Status ändern
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status ApprovedBy ApprovedAt )
WITH VALUE #( FOR travel IN lt_travel
( %tky = travel-%tky
Status = 'A'
ApprovedBy = cl_abap_context_info=>get_user_name( )
ApprovedAt = cl_abap_context_info=>get_system_date( ) ) )
FAILED failed
REPORTED reported.
" 3. Event auslösen
RAISE ENTITY EVENT zi_travel~TravelApproved
FROM VALUE #( FOR travel IN lt_travel
( %key-TravelId = travel-TravelId
%param-ApprovedBy = cl_abap_context_info=>get_user_name( )
%param-ApprovedAt = cl_abap_context_info=>get_system_date( )
%param-ApprovalNote = 'Approved via action' ) ).
" 4. Ergebnis zurückgeben
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
ENDCLASS.

Event in Validation/Determination

METHOD validateDates.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel).
IF ls_travel-EndDate < ls_travel-BeginDate.
" Validation-Fehler
APPEND VALUE #( %tky = ls_travel-%tky ) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Invalid date range'
)
) TO reported-travel.
" Event: ValidationFailed auslösen
RAISE ENTITY EVENT zi_travel~ValidationFailed
FROM VALUE #( ( %key-TravelId = ls_travel-TravelId
%param-ErrorType = 'DATE_RANGE'
%param-ErrorMessage = 'End date before begin date' ) ).
ENDIF.
ENDLOOP.
ENDMETHOD.

Mehrere Events

define behavior for ZI_Travel alias Travel
{
// Verschiedene Events für verschiedene Szenarien
event TravelCreated;
event TravelApproved;
event TravelRejected parameter ZA_RejectionParam;
event TravelCancelled;
event TravelCompleted;
}
METHOD approve.
" ...
RAISE ENTITY EVENT zi_travel~TravelApproved FROM ...
ENDMETHOD.
METHOD reject.
" ...
RAISE ENTITY EVENT zi_travel~TravelRejected
FROM VALUE #( ( %key-TravelId = ls_travel-TravelId
%param-RejectionReason = ls_key-%param-Reason ) ).
ENDMETHOD.
METHOD cancel.
" ...
RAISE ENTITY EVENT zi_travel~TravelCancelled FROM ...
ENDMETHOD.

Event Consumption (Subscriber)

Event Handler implementieren

CLASS zcl_travel_event_handler DEFINITION PUBLIC CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_rap_entity_event_subscriber.
ENDCLASS.
CLASS zcl_travel_event_handler IMPLEMENTATION.
METHOD if_rap_entity_event_subscriber~on_business_event.
" Event-Key auswerten
CASE event_key.
WHEN 'TravelApproved'.
handle_travel_approved( event_data ).
WHEN 'TravelRejected'.
handle_travel_rejected( event_data ).
WHEN 'TravelCancelled'.
handle_travel_cancelled( event_data ).
ENDCASE.
ENDMETHOD.
" Private Methoden für Event-Handling
METHODS:
handle_travel_approved
IMPORTING it_event_data TYPE STANDARD TABLE,
handle_travel_rejected
IMPORTING it_event_data TYPE STANDARD TABLE,
handle_travel_cancelled
IMPORTING it_event_data TYPE STANDARD TABLE.
ENDCLASS.

Event Handler registrieren

Service Definition:

@EndUserText.label: 'Travel Event Handler'
define service ZUI_TRAVEL_EVENTS {
expose ZI_Travel as Travel;
// Event Handler aktivieren
expose zcl_travel_event_handler as TravelEventHandler;
}

Oder: Programmatische Registrierung:

" In Initialisierungsklasse oder beim Systemstart
DATA(lo_event_handler) = NEW zcl_travel_event_handler( ).
" Handler registrieren
cl_rap_event_handler=>register(
iv_event_name = 'TravelApproved'
io_handler = lo_event_handler
).

Event-Daten verarbeiten

METHOD handle_travel_approved.
" Event-Daten sind eine Tabelle (kann mehrere Events sein)
LOOP AT it_event_data INTO DATA(ls_event).
" %key und %param extrahieren
DATA(lv_travel_id) = ls_event-%key-TravelId.
DATA(lv_approved_by) = ls_event-%param-ApprovedBy.
DATA(lv_approved_at) = ls_event-%param-ApprovedAt.
" 1. Email senden
send_approval_email(
iv_travel_id = lv_travel_id
iv_approved_by = lv_approved_by
).
" 2. Analytics tracken
track_approval_analytics(
iv_travel_id = lv_travel_id
iv_approved_at = lv_approved_at
).
" 3. Externe API benachrichtigen
notify_external_system(
iv_travel_id = lv_travel_id
).
" 4. Loggen
cl_bali_log=>create( )->add_item(
cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_information
text = |Travel { lv_travel_id } approved by { lv_approved_by }|
)
)->save( ).
ENDLOOP.
ENDMETHOD.

Fehlerbehandlung im Consumer

METHOD handle_travel_approved.
LOOP AT it_event_data INTO DATA(ls_event).
" Email-Versand mit Fehlerbehandlung
TRY.
send_approval_email( ls_event-%key-TravelId ).
CATCH cx_email_error INTO DATA(lx_email).
" Fehler loggen, aber Event-Verarbeitung NICHT abbrechen
cl_bali_log=>create( )->add_item(
cl_bali_message_setter=>create_from_exception( lx_email )
)->save( ).
" Optional: Retry-Logik
add_to_retry_queue(
iv_event_type = 'TravelApproved'
iv_travel_id = ls_event-%key-TravelId
).
ENDTRY.
" API-Call mit Fehlerbehandlung
TRY.
notify_external_system( ls_event-%key-TravelId ).
CATCH cx_http_error INTO DATA(lx_http).
" Fehler loggen
cl_bali_log=>create( )->add_item(
cl_bali_message_setter=>create_from_exception( lx_http )
)->save( ).
ENDTRY.
ENDLOOP.
ENDMETHOD.

Praktische Use Cases

Use Case 1: Multi-Channel Benachrichtigung

" Event: TravelApproved
" → Consumer 1: Email
" → Consumer 2: SMS
" → Consumer 3: Push Notification
" → Consumer 4: Slack
CLASS zcl_notification_handler DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_rap_entity_event_subscriber.
ENDCLASS.
CLASS zcl_notification_handler IMPLEMENTATION.
METHOD if_rap_entity_event_subscriber~on_business_event.
CHECK event_key = 'TravelApproved'.
LOOP AT event_data INTO DATA(ls_event).
DATA(lv_travel_id) = ls_event-%key-TravelId.
" Kunde-Präferenzen laden
SELECT SINGLE * FROM zcustomer_prefs
WHERE travel_id = @lv_travel_id
INTO @DATA(ls_prefs).
" Multi-Channel Benachrichtigung (parallel)
IF ls_prefs-notify_email = abap_true.
send_email( lv_travel_id ).
ENDIF.
IF ls_prefs-notify_sms = abap_true.
send_sms( lv_travel_id ).
ENDIF.
IF ls_prefs-notify_push = abap_true.
send_push_notification( lv_travel_id ).
ENDIF.
IF ls_prefs-notify_slack = abap_true.
send_slack_message( lv_travel_id ).
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Use Case 2: Audit Trail

CLASS zcl_audit_trail_handler DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_rap_entity_event_subscriber.
ENDCLASS.
CLASS zcl_audit_trail_handler IMPLEMENTATION.
METHOD if_rap_entity_event_subscriber~on_business_event.
" Alle Events auditen
LOOP AT event_data INTO DATA(ls_event).
" Audit-Eintrag erstellen
INSERT INTO zaudit_log VALUES (
audit_id = cl_uuid_factory=>create_system_uuid( )->create_uuid_x16( )
entity_type = 'TRAVEL'
entity_key = ls_event-%key-TravelId
event_type = event_key
event_date = sy-datum
event_time = sy-uzeit
user_name = sy-uname
event_payload = /ui2/cl_json=>serialize( ls_event )
).
ENDLOOP.
COMMIT WORK.
ENDMETHOD.
ENDCLASS.

Use Case 3: Workflow Trigger

CLASS zcl_workflow_trigger_handler DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_rap_entity_event_subscriber.
ENDCLASS.
CLASS zcl_workflow_trigger_handler IMPLEMENTATION.
METHOD if_rap_entity_event_subscriber~on_business_event.
CHECK event_key = 'TravelApproved'.
LOOP AT event_data INTO DATA(ls_event).
DATA(lv_travel_id) = ls_event-%key-TravelId.
" Travel-Details laden
SELECT SINGLE * FROM zi_travel
WHERE TravelId = @lv_travel_id
INTO @DATA(ls_travel).
" Workflow triggern für teure Reisen
IF ls_travel-TotalAmount > 10000.
" SAP Build Process Automation Workflow starten
DATA(lo_workflow) = cl_spa_workflow=>get_instance( ).
lo_workflow->start_workflow(
workflow_id = 'HighValueTravelApproval'
context = VALUE #(
travel_id = lv_travel_id
amount = ls_travel-TotalAmount
approved_by = ls_event-%param-ApprovedBy
)
).
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Use Case 4: Cache Invalidation

CLASS zcl_cache_handler DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_rap_entity_event_subscriber.
ENDCLASS.
CLASS zcl_cache_handler IMPLEMENTATION.
METHOD if_rap_entity_event_subscriber~on_business_event.
" Bei allen Travel-Events: Cache invalidieren
CASE event_key.
WHEN 'TravelApproved' OR 'TravelRejected' OR 'TravelCancelled'.
LOOP AT event_data INTO DATA(ls_event).
" Cache für diese Travel löschen
cl_cache_manager=>invalidate(
cache_area = 'TRAVEL'
key = ls_event-%key-TravelId
).
" Optional: Related Caches auch löschen
" (z.B. Customer-Travel-List)
SELECT SINGLE CustomerId FROM zi_travel
WHERE TravelId = @ls_event-%key-TravelId
INTO @DATA(lv_customer_id).
cl_cache_manager=>invalidate(
cache_area = 'CUSTOMER_TRAVELS'
key = lv_customer_id
).
ENDLOOP.
ENDCASE.
ENDMETHOD.
ENDCLASS.

Integration mit SAP Event Mesh

Event Mesh Setup

Was ist SAP Event Mesh?

  • Cloud-Service für Enterprise Event Bus
  • Entkoppelt Publisher und Consumer über Message Queue
  • Unterstützt Pub/Sub-Pattern
  • Multi-Tenant, skalierbar, hochverfügbar

Event nach Event Mesh publishen

CLASS zcl_event_mesh_publisher DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_rap_entity_event_subscriber.
ENDCLASS.
CLASS zcl_event_mesh_publisher IMPLEMENTATION.
METHOD if_rap_entity_event_subscriber~on_business_event.
" RAP Event nach Event Mesh weiterleiten
LOOP AT event_data INTO DATA(ls_event).
" Event als JSON serialisieren
DATA(lv_json_payload) = /ui2/cl_json=>serialize(
data = ls_event
compress = abap_false
).
" HTTP Client für Event Mesh
DATA(lo_http) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = cl_http_destination_provider=>create_by_cloud_destination(
i_name = 'EVENT_MESH'
i_authn_mode = if_a4c_cp_service=>service_specific
)
).
" POST Request
DATA(lo_request) = lo_http->get_http_request( ).
lo_request->set_header_field(
i_name = 'Content-Type'
i_value = 'application/json'
).
lo_request->set_header_field(
i_name = 'x-qos' " Quality of Service
i_value = '1' " At least once
).
lo_request->set_text( lv_json_payload ).
" Event Topic
DATA(lv_topic) = |sap/s4/travel/{ event_key }|.
TRY.
DATA(lo_response) = lo_http->execute(
i_method = if_web_http_client=>post
i_uri = |/messagingrest/v1/topics/{ lv_topic }/messages|
).
IF lo_response->get_status( )-code = 204.
" Erfolgreich published
cl_bali_log=>create( )->add_item(
cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_information
text = |Event { event_key } published to Event Mesh|
)
)->save( ).
ENDIF.
CATCH cx_web_http_client_error INTO DATA(lx_http).
" Fehler loggen
cl_bali_log=>create( )->add_item(
cl_bali_message_setter=>create_from_exception( lx_http )
)->save( ).
ENDTRY.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Event von Event Mesh consumieren

" Webhook Endpoint für Event Mesh Callbacks
CLASS zcl_event_mesh_consumer DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES if_http_service_extension.
ENDCLASS.
CLASS zcl_event_mesh_consumer IMPLEMENTATION.
METHOD if_http_service_extension~handle_request.
" Event Mesh sendet Events via HTTP POST
" JSON Payload extrahieren
DATA(lv_payload) = request->get_text( ).
" Deserialisieren
DATA ls_event TYPE zi_travel_event.
/ui2/cl_json=>deserialize(
EXPORTING json = lv_payload
CHANGING data = ls_event
).
" Event verarbeiten
CASE ls_event-event_type.
WHEN 'TravelApproved'.
" Lokale Verarbeitung
process_travel_approved( ls_event ).
WHEN 'TravelRejected'.
process_travel_rejected( ls_event ).
ENDCASE.
" Response
response->set_status( i_code = 200 i_reason = 'OK' ).
ENDMETHOD.
ENDCLASS.

Testing von Events

Event Raising testen

CLASS ltc_travel_events DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_environment TYPE REF TO if_cds_test_environment.
METHODS:
setup,
teardown,
test_approve_raises_event FOR TESTING.
ENDCLASS.
CLASS ltc_travel_events IMPLEMENTATION.
METHOD setup.
mo_environment = cl_cds_test_environment=>create(
i_for_entity = 'ZI_Travel'
).
" Testdaten
mo_environment->insert_test_data(
i_data = VALUE zi_travel(
( TravelId = '00000001' Status = 'O' CustomerId = '000042' )
)
).
ENDMETHOD.
METHOD test_approve_raises_event.
" Arrange: Event Spy registrieren
DATA(lo_event_spy) = NEW lcl_event_spy( ).
" (In echten Tests: Framework-spezifischer Spy)
" Act: Action ausführen (sollte Event raisen)
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE approve FROM VALUE #( ( TravelId = '00000001' ) )
FAILED DATA(failed).
COMMIT ENTITIES.
" Assert: Event wurde ausgelöst
" (Framework-abhängig - hier konzeptuell)
cl_abap_unit_assert=>assert_equals(
exp = 1
act = lo_event_spy->get_event_count( 'TravelApproved' )
msg = 'Event TravelApproved should be raised'
).
" Assert: Event-Parameter korrekt
DATA(ls_event) = lo_event_spy->get_event( 'TravelApproved' ).
cl_abap_unit_assert=>assert_equals(
exp = '00000001'
act = ls_event-%key-TravelId
).
ENDMETHOD.
METHOD teardown.
ROLLBACK ENTITIES.
mo_environment->destroy( ).
ENDMETHOD.
ENDCLASS.

Event Handler testen

CLASS ltc_event_handler DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
DATA mo_cut TYPE REF TO zcl_travel_event_handler.
METHODS:
setup,
test_handle_approved_event FOR TESTING.
ENDCLASS.
CLASS ltc_event_handler IMPLEMENTATION.
METHOD setup.
mo_cut = NEW zcl_travel_event_handler( ).
ENDMETHOD.
METHOD test_handle_approved_event.
" Arrange: Mock Event Data
DATA(lt_event_data) = VALUE zi_travel_event_tab(
( %key-TravelId = '00000001'
%param-ApprovedBy = 'TEST_USER'
%param-ApprovedAt = '20250101' )
).
" Act
mo_cut->if_rap_entity_event_subscriber~on_business_event(
event_key = 'TravelApproved'
event_data = lt_event_data
).
" Assert: Prüfen dass Handler korrekt verarbeitet hat
" (z.B. Email gesendet, Log-Eintrag erstellt)
" → Hängt von Implementation ab
ENDMETHOD.
ENDCLASS.

Event Patterns

Pattern 1: Event Chaining

" Event 1 triggert Event 2 triggert Event 3
" Publisher 1
METHOD create_travel.
" ...
RAISE ENTITY EVENT zi_travel~TravelCreated FROM ...
ENDMETHOD.
" Consumer 1 = Publisher 2
CLASS zcl_handler_1 IMPLEMENTATION.
METHOD on_business_event.
CHECK event_key = 'TravelCreated'.
" Validation durchführen
validate_travel( event_data ).
" Nächstes Event
RAISE ENTITY EVENT zi_travel~TravelValidated FROM ...
ENDMETHOD.
ENDCLASS.
" Consumer 2 = Publisher 3
CLASS zcl_handler_2 IMPLEMENTATION.
METHOD on_business_event.
CHECK event_key = 'TravelValidated'.
" Approval-Prozess starten
start_approval( event_data ).
" Nächstes Event
RAISE ENTITY EVENT zi_travel~ApprovalStarted FROM ...
ENDMETHOD.
ENDCLASS.

Pattern 2: Event Aggregation

" Mehrere Events zu einem Summary-Event aggregieren
CLASS zcl_event_aggregator IMPLEMENTATION.
METHOD on_business_event.
" Events sammeln
CASE event_key.
WHEN 'TravelApproved' OR 'TravelRejected' OR 'TravelCancelled'.
" In-Memory Counter
add_to_statistics( event_key ).
ENDCASE.
" Jede Stunde: Summary-Event
IF hour_passed( ).
RAISE EVENT DailySummary
FROM VALUE #( ( approvals = mv_approval_count
rejections = mv_rejection_count
cancellations = mv_cancellation_count ) ).
reset_statistics( ).
ENDIF.
ENDMETHOD.
ENDCLASS.

Pattern 3: Event Filtering

" Nur bestimmte Events weiterverarbeiten
CLASS zcl_high_value_handler IMPLEMENTATION.
METHOD on_business_event.
CHECK event_key = 'TravelCreated'.
LOOP AT event_data INTO DATA(ls_event).
" Travel-Details laden
SELECT SINGLE TotalAmount FROM zi_travel
WHERE TravelId = @ls_event-%key-TravelId
INTO @DATA(lv_amount).
" Nur High-Value Travels (> 10.000)
CHECK lv_amount > 10000.
" Special Handling
notify_manager( ls_event-%key-TravelId ).
require_additional_approval( ls_event-%key-TravelId ).
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Wichtige Hinweise / Best Practice

  • Loose Coupling: Events entkoppeln Publisher und Consumer
  • Asynchron: Events ermöglichen asynchrone Verarbeitung
  • Fire & Forget: Publisher kümmert sich nicht um Consumer-Erfolg
  • Idempotenz: Event Handler sollten idempotent sein (mehrfaches Verarbeiten = OK)
  • Fehlerbehandlung: Consumer-Fehler dürfen Publisher nicht beeinflussen
  • Event Naming: Vergangenheitsform (TravelApproved, nicht ApproveTravel)
  • Event Payload: Nur notwendige Daten (keine großen Objekte)
  • Versionierung: Event-Struktur nie brechen (nur erweitern)
  • Testing: Events explizit testen (Spy-Pattern)
  • Monitoring: Event-Verarbeitung loggen und monitoren
  • Retry-Logic: Fehlgeschlagene Events in Queue für Retry
  • Event Mesh: Für System-übergreifende Events nutzen
  • Documentation: Events und ihre Consumer dokumentieren

Weitere Ressourcen