SAP Event Mesh avec ABAP Cloud : Architecture event-driven

Catégorie
Integration
Publié
Auteur
Johannes

SAP Event Mesh permet une communication faiblement couplée et basée sur les événements entre les systèmes ABAP et d’autres applications sur la SAP Business Technology Platform. Avec les RAP Business Events, vous pouvez définir des événements métier et les propager en temps réel vers des systèmes externes.

Qu’est-ce que l’architecture event-driven ?

L’architecture event-driven (EDA) est un modèle d’architecture dans lequel les systèmes communiquent via des événements plutôt que par des appels API directs :

AspectIntégration directeEvent-driven
CouplageÉtroit (synchrone)Faible (asynchrone)
DisponibilitéDépendant du système cibleIndépendant
ÉvolutivitéLimitéeÉlevée
Tolérance aux pannesFaibleÉlevée (Retry/Replay)
LatenceSynchroneAsynchrone
Cas d’utilisationCohérence transactionnelleNotifications, réplication

Concept SAP Event Mesh

SAP Event Mesh est un service de messagerie entièrement géré sur BTP :

┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ ABAP Cloud │ │ SAP Event Mesh │ │ Subscriber │
│ (Publisher) │─────>│ (Message Broker)│─────>│ (Consumer) │
│ │ │ │ │ │
│ RAP Business │ │ - Queues │ │ - ABAP Cloud │
│ Events │ │ - Topics │ │ - CAP App │
│ │ │ - Subscriptions │ │ - 3rd Party │
└─────────────────┘ └──────────────────┘ └─────────────────┘

Concepts clés :

  • Event : Message concernant un événement métier (par ex. “Commande créée”)
  • Topic : Canal logique pour les événements (par ex. “sap/sales/order/created”)
  • Queue : Stockage persistant pour les événements par abonné
  • Subscription : Connexion entre le Topic et la Queue

Définir un RAP Business Event

Les Business Events sont déclarés dans la Behavior Definition et déclenchés lors des changements d’état.

Behavior Definition avec Events

managed implementation in class zbp_i_salesorder unique;
strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrder
persistent table zsalesorder
lock master
authorization master ( instance )
etag master LastChangedAt
with additional save
{
create;
update;
delete;
// Définir les Business Events
event created;
event updated;
event deleted;
event statusChanged parameter ZA_StatusChangeInfo;
}

Event avec structure de paramètres

Pour les événements complexes, vous définissez une Abstract Entity comme paramètre :

@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;
}

Publication d’événements

Les événements sont déclenchés dans l’implémentation du Behavior - généralement dans des Determinations ou Actions.

Déclencher un événement lors du Create

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.
" Déclencher l'événement pour les nouvelles instances
RAISE ENTITY EVENT zi_salesorder~created
FROM VALUE #( FOR key IN keys
( %key = key-%key ) ).
ENDMETHOD.
ENDCLASS.

Event lors d’un changement de statut avec paramètres

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.
" Lire les anciennes et nouvelles valeurs
READ ENTITIES OF zi_salesorder IN LOCAL MODE
ENTITY SalesOrder
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(orders).
" Déclencher l'événement avec paramètres
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 pour le déclenchement d’événements

managed implementation in class zbp_i_salesorder unique;
strict ( 2 );
define behavior for ZI_SalesOrder alias SalesOrder
persistent table zsalesorder
lock master
authorization master ( instance )
with additional save
{
create;
update;
delete;
// Events
event created;
event statusChanged parameter ZA_StatusChangeInfo;
// Determinations pour le déclenchement d'événements
determination raiseCreatedEvent on save { create; }
determination onStatusChange on save { field Status; }
}

Consommation d’événements

Les événements peuvent être consommés dans d’autres systèmes ABAP ou applications externes.

Event Handler dans 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.
" Vérifier le type d'événement
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.
" Lire les données de l'événement
io_event->get_business_data( IMPORTING et_business_data = lt_keys ).
" Traitement : par ex. envoyer un message, écrire un log
LOOP AT lt_keys INTO DATA(ls_key).
" Logique métier
ENDLOOP.
ENDMETHOD.
METHOD handle_status_changed.
DATA: lt_params TYPE TABLE OF za_statuschangeinfo.
" Lire les données des paramètres
io_event->get_business_data( IMPORTING et_business_data = lt_params ).
LOOP AT lt_params INTO DATA(ls_param).
" Par ex. envoyer un e-mail lors du changement de statut
IF ls_param-newstatus = 'AP'. " Approved
send_approval_notification( ls_param ).
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Enregistrer un Event Handler

L’enregistrement se fait via le Business Event Handling Framework :

" Enregistrement dans une table de customizing ou par API
DATA(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' ).

Configuration dans le cockpit BTP

1. Créer le service Event Mesh

  1. Dans le cockpit BTP, naviguez vers votre Subaccount
  2. Allez dans Service MarketplaceSAP Event Mesh
  3. Créez une instance de service avec le plan default
  4. Créez une Service Key pour l’authentification

2. Configurer le Message Client

Les données de la Service Key contiennent tous les paramètres de connexion nécessaires :

{
"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 dans le système ABAP

┌──────────────────────────────────────────────────────────────┐
│ 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. Configurer le Channel

Dans le système ABAP sous Enterprise Event Enablement :

" Créer un Event Channel
DATA(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-Binding
lo_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' ).

Consommation d’événements dans des systèmes externes

Application CAP (Node.js)

const cds = require('@sap/cds');
module.exports = async (srv) => {
// Connexion Event Mesh
const messaging = await cds.connect.to('messaging');
// Enregistrer les Event Handlers
messaging.on('sap/salesorder/created/v1', async (msg) => {
const { SalesOrderId } = msg.data;
console.log(`New sales order created: ${SalesOrderId}`);
// Logique métier
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}`);
});
};

Consumer Python

from sap_event_mesh_client import EventMeshClient
# Initialiser le client
client = EventMeshClient(
service_key_path='event-mesh-service-key.json"
)
# S'abonner à une queue
@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}')
# Logique métier
message.ack() # Confirmer le message
# Démarrer le consumer
client.start()

Exemple complet : Pipeline de traitement des commandes

Business Object avec Events

managed implementation in class zbp_i_purchaseorder unique;
strict ( 2 );
define behavior for ZI_PurchaseOrder alias PurchaseOrder
persistent table zpurchaseorder
lock master
authorization master ( instance )
etag master LastChangedAt
with additional save
{
create;
update;
delete;
// Actions
action ( features : instance ) approve result [1] $self;
action ( features : instance ) reject result [1] $self;
// Events pour chaque changement d'état important
event created;
event approved parameter ZA_ApprovalInfo;
event rejected parameter ZA_RejectionInfo;
event amountChanged parameter ZA_AmountChangeInfo;
// Triggers
determination triggerCreated on save { create; }
determination triggerAmountChange on save { field TotalAmount; }
}

Paramètres d’événements

@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);
}

Implémentation d’Action avec Event

CLASS lhc_purchaseorder IMPLEMENTATION.
METHOD approve.
" Mettre à jour le statut
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.
" Lire le résultat
READ ENTITIES OF zi_purchaseorder IN LOCAL MODE
ENTITY PurchaseOrder
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(orders).
" Déclencher l'événement
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 ) ) ).
" Retourner le résultat
result = VALUE #( FOR order IN orders
( %tky = order-%tky
%param = order ) ).
ENDMETHOD.
ENDCLASS.

Bonnes pratiques

SujetRecommandation
Granularité des événementsUn événement par événement métier, pas trop granulaire
IdempotenceLes consumers doivent pouvoir traiter les événements en double
Schéma d’événementsRespecter le versionnement (v1, v2), éviter les breaking changes
ParamètresUniquement les données nécessaires dans l’événement, pas l’entité entière
Gestion des erreursConfigurer une Dead-Letter-Queue pour les événements échoués
MonitoringUtiliser le dashboard SAP Event Mesh pour les métriques
TestsTester les événements localement avant l’intégration en production
SécuritéService Keys séparées pour le développement et la production

Sujets connexes