Business Events en RAP habilitan arquitectura orientada a eventos: En lugar de llamadas directas a métodos, los componentes se comunican a través de eventos. Esto desacopla sistemas, permite el procesamiento asíncrono y hace que las arquitecturas sean más escalables y mantenibles.
El problema: Acoplamiento fuerte
Sin eventos (Acoplamiento fuerte)
" ❌ Dependencia directa: Travel → Email → LoggingMETHOD approve_travel. " 1. Cambiar estado MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( Status ) WITH VALUE #( ( %tky = ls_travel-%tky Status = 'A' ) ).
" 2. Enviar email (¡dependencia directa!) TRY. cl_email_sender=>send( recipient = ls_travel-customer_email subject = 'Travel approved' ). CATCH cx_email_error. " ¿Qué hacer en caso de error? ENDTRY.
" 3. Registrar log (¡dependencia directa!) cl_logger=>log( |Travel { ls_travel-TravelId } approved| ).
" 4. Actualizar Analytics (¡dependencia directa!) zcl_analytics=>track_approval( ls_travel-TravelId ).
" 5. Notificar sistema externo (¡dependencia directa!) zcl_external_api=>notify_approval( ls_travel ).ENDMETHOD.Problemas:
- 🔴 Acoplamiento fuerte: La lógica de aprobación conoce todos los consumidores
- 🔴 Síncrono: Todos los pasos bloquean el proceso principal
- 🔴 No extensible: Nuevo consumidor = cambiar código
- 🔴 Propenso a errores: Un consumidor fallido interrumpe todo
- 🔴 Lento: Email + API + Logging = 2-3 segundos
Con eventos (Acoplamiento débil)
" ✅ Orientado a eventos: Travel → Event → Consumers (desacoplado)METHOD approve_travel. " 1. Cambiar estado MODIFY ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel UPDATE FIELDS ( Status ) WITH VALUE #( ( %tky = ls_travel-%tky Status = 'A' ) ).
" 2. Disparar evento (Fire & Forget) RAISE ENTITY EVENT zi_travel~TravelApproved FROM VALUE #( ( %key-TravelId = ls_travel-TravelId %param-ApprovedBy = sy-uname %param-ApprovedAt = sy-datum ) ).
" ¡Listo! Los consumidores reaccionan de forma asíncronaENDMETHOD.Ventajas:
- ✅ Acoplamiento débil: La lógica de aprobación no conoce consumidores
- ✅ Asíncrono: Los consumidores procesan en paralelo
- ✅ Extensible: Nuevos consumidores sin cambiar código
- ✅ Resiliente: Errores del consumidor no afectan el proceso principal
- ✅ Rápido: El proceso principal continúa inmediatamente (< 100ms)
Anatomía de un evento
┌─────────────────────────────────────────────────────┐│ 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( ) │└────────────────────┘Definición de eventos en BDEF
Evento simple
define behavior for ZI_Travel alias Travelpersistent table ztravellock masterauthorization master ( instance ){ create; update; delete;
// Definición de evento event TravelApproved;
// Acción que dispara el evento action approve result [1] $self;}Evento con parámetros
define behavior for ZI_Travel alias Travel{ // Evento con estructura de parámetros event TravelApproved parameter ZA_TravelApprovedParam;
action approve result [1] $self;}Estructura de parámetros (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);}Evento con parámetro estándar
define behavior for ZI_Travel alias Travel{ // Evento con %param predefinido event TravelApproved parameter ZA_TravelApprovedParam;
// O: Solo campos clave (sin parámetro explícito) event TravelCancelled;}Disparo de eventos (Publisher)
Disparar evento en Action
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. Leer datos READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(lt_travel) FAILED failed REPORTED reported.
" 2. Cambiar estado 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. Disparar evento 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. Devolver resultado READ ENTITIES OF zi_travel IN LOCAL MODE ENTITY Travel ALL FIELDS WITH CORRESPONDING #( keys ) RESULT result. ENDMETHOD.
ENDCLASS.Evento en 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. " Error de validación 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.
" Evento: Disparar ValidationFailed 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.Múltiples eventos
define behavior for ZI_Travel alias Travel{ // Diferentes eventos para diferentes escenarios 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.Consumo de eventos (Subscriber)
Implementar Event Handler
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. " Evaluar event-key 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.
" Métodos privados para manejo de eventos 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.Registrar Event Handler
Service Definition:
@EndUserText.label: 'Travel Event Handler'define service ZUI_TRAVEL_EVENTS { expose ZI_Travel as Travel;
// Activar Event Handler expose zcl_travel_event_handler as TravelEventHandler;}O: Registro programático:
" En clase de inicialización o al inicio del sistemaDATA(lo_event_handler) = NEW zcl_travel_event_handler( ).
" Registrar handlercl_rap_event_handler=>register( iv_event_name = 'TravelApproved' io_handler = lo_event_handler).Procesar datos del evento
METHOD handle_travel_approved. " Los datos del evento son una tabla (pueden ser múltiples eventos) LOOP AT it_event_data INTO DATA(ls_event).
" Extraer %key y %param 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. Enviar email send_approval_email( iv_travel_id = lv_travel_id iv_approved_by = lv_approved_by ).
" 2. Rastrear analytics track_approval_analytics( iv_travel_id = lv_travel_id iv_approved_at = lv_approved_at ).
" 3. Notificar API externa notify_external_system( iv_travel_id = lv_travel_id ).
" 4. Registrar log 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.Manejo de errores en Consumer
METHOD handle_travel_approved. LOOP AT it_event_data INTO DATA(ls_event).
" Envío de email con manejo de errores TRY. send_approval_email( ls_event-%key-TravelId ). CATCH cx_email_error INTO DATA(lx_email). " Registrar error, pero NO interrumpir procesamiento del evento cl_bali_log=>create( )->add_item( cl_bali_message_setter=>create_from_exception( lx_email ) )->save( ).
" Opcional: Lógica de reintentos add_to_retry_queue( iv_event_type = 'TravelApproved' iv_travel_id = ls_event-%key-TravelId ). ENDTRY.
" Llamada API con manejo de errores TRY. notify_external_system( ls_event-%key-TravelId ). CATCH cx_http_error INTO DATA(lx_http). " Registrar error cl_bali_log=>create( )->add_item( cl_bali_message_setter=>create_from_exception( lx_http ) )->save( ). ENDTRY.
ENDLOOP.ENDMETHOD.Casos de uso prácticos
Caso de uso 1: Notificación multicanal
" Evento: 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.
" Cargar preferencias del cliente SELECT SINGLE * FROM zcustomer_prefs WHERE travel_id = @lv_travel_id INTO @DATA(ls_prefs).
" Notificación multicanal (paralelo) 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.Caso de uso 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. " Auditar todos los eventos LOOP AT event_data INTO DATA(ls_event).
" Crear entrada de auditoría 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.Caso de uso 3: Disparador de Workflow
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.
" Cargar detalles del viaje SELECT SINGLE * FROM zi_travel WHERE TravelId = @lv_travel_id INTO @DATA(ls_travel).
" Disparar workflow para viajes costosos IF ls_travel-TotalAmount > 10000.
" Iniciar workflow de SAP Build Process Automation 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.Caso de uso 4: Invalidación de caché
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. " Para todos los eventos de Travel: Invalidar caché CASE event_key. WHEN 'TravelApproved' OR 'TravelRejected' OR 'TravelCancelled'.
LOOP AT event_data INTO DATA(ls_event). " Eliminar caché para este Travel cl_cache_manager=>invalidate( cache_area = 'TRAVEL' key = ls_event-%key-TravelId ).
" Opcional: Eliminar cachés relacionados también " (por ejemplo, lista de viajes del cliente) 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.Integración con SAP Event Mesh
Configuración de Event Mesh
¿Qué es SAP Event Mesh?
- Servicio cloud para Enterprise Event Bus
- Desacopla Publisher y Consumer a través de Message Queue
- Soporta patrón Pub/Sub
- Multi-tenant, escalable, alta disponibilidad
Publicar evento en Event Mesh
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. " Reenviar evento RAP a Event Mesh
LOOP AT event_data INTO DATA(ls_event).
" Serializar evento como JSON DATA(lv_json_payload) = /ui2/cl_json=>serialize( data = ls_event compress = abap_false ).
" Cliente HTTP para 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 ) ).
" Solicitud POST 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 ).
" Topic del evento 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. " Publicado exitosamente 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). " Registrar error cl_bali_log=>create( )->add_item( cl_bali_message_setter=>create_from_exception( lx_http ) )->save( ). ENDTRY.
ENDLOOP. ENDMETHOD.
ENDCLASS.Consumir evento desde Event Mesh
" Endpoint Webhook para callbacks de Event MeshCLASS 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 envía eventos vía HTTP POST
" Extraer payload JSON DATA(lv_payload) = request->get_text( ).
" Deserializar DATA ls_event TYPE zi_travel_event. /ui2/cl_json=>deserialize( EXPORTING json = lv_payload CHANGING data = ls_event ).
" Procesar evento CASE ls_event-event_type. WHEN 'TravelApproved'. " Procesamiento local process_travel_approved( ls_event ).
WHEN 'TravelRejected'. process_travel_rejected( ls_event ). ENDCASE.
" Respuesta response->set_status( i_code = 200 i_reason = 'OK' ).
ENDMETHOD.
ENDCLASS.Testing de eventos
Probar disparo de eventos
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' ).
" Datos de prueba mo_environment->insert_test_data( i_data = VALUE zi_travel( ( TravelId = '00000001' Status = 'O' CustomerId = '000042' ) ) ). ENDMETHOD.
METHOD test_approve_raises_event. " Arrange: Registrar Event Spy DATA(lo_event_spy) = NEW lcl_event_spy( ). " (En pruebas reales: Spy específico del framework)
" Act: Ejecutar action (debería disparar evento) MODIFY ENTITIES OF zi_travel ENTITY Travel EXECUTE approve FROM VALUE #( ( TravelId = '00000001' ) ) FAILED DATA(failed).
COMMIT ENTITIES.
" Assert: El evento fue disparado " (Dependiente del framework - aquí conceptual) cl_abap_unit_assert=>assert_equals( exp = 1 act = lo_event_spy->get_event_count( 'TravelApproved' ) msg = 'Event TravelApproved should be raised' ).
" Assert: Parámetros del evento correctos 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.Probar Event Handler
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: Verificar que el handler procesó correctamente " (por ejemplo, email enviado, entrada de log creada) " → Depende de la implementación ENDMETHOD.
ENDCLASS.Patrones de eventos
Patrón 1: Encadenamiento de eventos
" Evento 1 dispara Evento 2 dispara Evento 3
" Publisher 1METHOD create_travel. " ... RAISE ENTITY EVENT zi_travel~TravelCreated FROM ...ENDMETHOD.
" Consumer 1 = Publisher 2CLASS zcl_handler_1 IMPLEMENTATION. METHOD on_business_event. CHECK event_key = 'TravelCreated'.
" Realizar validación validate_travel( event_data ).
" Siguiente evento RAISE ENTITY EVENT zi_travel~TravelValidated FROM ... ENDMETHOD.ENDCLASS.
" Consumer 2 = Publisher 3CLASS zcl_handler_2 IMPLEMENTATION. METHOD on_business_event. CHECK event_key = 'TravelValidated'.
" Iniciar proceso de aprobación start_approval( event_data ).
" Siguiente evento RAISE ENTITY EVENT zi_travel~ApprovalStarted FROM ... ENDMETHOD.ENDCLASS.Patrón 2: Agregación de eventos
" Agregar múltiples eventos en un evento resumen
CLASS zcl_event_aggregator IMPLEMENTATION. METHOD on_business_event. " Recopilar eventos CASE event_key. WHEN 'TravelApproved' OR 'TravelRejected' OR 'TravelCancelled'. " Contador en memoria add_to_statistics( event_key ). ENDCASE.
" Cada hora: Evento resumen 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.Patrón 3: Filtrado de eventos
" Procesar solo ciertos eventos
CLASS zcl_high_value_handler IMPLEMENTATION. METHOD on_business_event. CHECK event_key = 'TravelCreated'.
LOOP AT event_data INTO DATA(ls_event). " Cargar detalles del viaje SELECT SINGLE TotalAmount FROM zi_travel WHERE TravelId = @ls_event-%key-TravelId INTO @DATA(lv_amount).
" Solo viajes de alto valor (> 10.000) CHECK lv_amount > 10000.
" Manejo especial notify_manager( ls_event-%key-TravelId ). require_additional_approval( ls_event-%key-TravelId ). ENDLOOP. ENDMETHOD.ENDCLASS.Notas importantes / Mejores prácticas
- Acoplamiento débil: Los eventos desacoplan Publisher y Consumer
- Asíncrono: Los eventos permiten procesamiento asíncrono
- Fire & Forget: El Publisher no se preocupa por el éxito del Consumer
- Idempotencia: Los Event Handlers deben ser idempotentes (múltiples procesamientos = OK)
- Manejo de errores: Errores del Consumer no deben afectar al Publisher
- Nomenclatura de eventos: Tiempo pasado (
TravelApproved, noApproveTravel) - Payload del evento: Solo datos necesarios (no objetos grandes)
- Versionado: Nunca romper la estructura del evento (solo extender)
- Testing: Probar eventos explícitamente (patrón Spy)
- Monitoreo: Registrar y monitorear el procesamiento de eventos
- Lógica de reintentos: Eventos fallidos en cola para reintento
- Event Mesh: Usar para eventos entre sistemas
- Documentación: Documentar eventos y sus consumidores
Recursos adicionales
- Fundamentos de RAP: /es/blog/rap-basics/
- Guía EML: /es/blog/eml-entity-manipulation-language/
- RAP Determinations/Validations: /es/blog/rap-determinations-validations/
- ABAP Cloud: /es/blog/abap-cloud-definition/