RFC dans ABAP Cloud : Scénarios de communication

Catégorie
Integration
Publié
Auteur
Johannes

Remote Function Call (RFC) permet la communication synchrone entre systèmes SAP. Dans ABAP Cloud, les connexions RFC sont configurées via les Communication Arrangements et le Destination Service pour garantir une intégration sécurisée et maintenable.

RFC dans ABAP Cloud vs. ABAP classique

La communication RFC dans ABAP Cloud diffère fondamentalement de l’approche classique :

AspectABAP classiqueABAP Cloud
ConfigurationSM59 RFC-DestinationCommunication Arrangement
AppelCALL FUNCTION … DESTINATIONClasses proxy via IF_PROXY_CLIENT
AuthentificationStockée dans SM59OAuth2, Certificats, Principal Propagation
MonitoringSMGW, ST22SAP Cloud ALM, BTP Cockpit
Gestion des erreursCOMMUNICATION_FAILUREClasses d’exception
DisponibilitéTous les FuBasUniquement les FuBas remote-enabled publiés

Scénarios de communication

Vue d’ensemble des scénarios

Il existe trois scénarios principaux pour RFC dans ABAP Cloud :

┌─────────────────────────────────────────────────────────────────┐
│ Scénario 1 : Cloud-to-Cloud │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ ABAP Cloud │─────>│ ABAP Cloud │ │
│ │ (BTP) │ RFC │ (BTP) │ │
│ └──────────────┘ └──────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Scénario 2 : Cloud-to-On-Premise (via Cloud Connector) │
│ ┌──────────────┐ ┌───────────────┐ ┌──────────────┐ │
│ │ ABAP Cloud │─────>│ SAP Cloud │─────>│ S/4HANA │ │
│ │ (BTP) │ │ Connector │ │ On-Premise │ │
│ └──────────────┘ └───────────────┘ └──────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Scénario 3 : On-Premise-to-Cloud │
│ ┌──────────────┐ ┌───────────────┐ ┌──────────────┐ │
│ │ S/4HANA │─────>│ SAP Cloud │─────>│ ABAP Cloud │ │
│ │ On-Premise │ │ Connector │ │ (BTP) │ │
│ └──────────────┘ └───────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘

RFC Cloud-to-Cloud

Pour la communication Cloud-to-Cloud, deux instances ABAP Environment se connectent directement :

Avantages :

  • Aucune infrastructure supplémentaire nécessaire
  • Authentification OAuth2 automatique
  • Haute disponibilité grâce à l’infrastructure BTP

Limitations :

  • Uniquement les Function Modules remote-enabled
  • Pas de BAPIs classiques (uniquement les APIs publiées)

RFC Cloud-to-On-Premise

Pour la connexion aux systèmes On-Premise, le SAP Cloud Connector est nécessaire :

Composants :

  • SAP Cloud Connector installé dans le réseau local
  • Virtual Host Mapping pour la passerelle RFC
  • Principal Propagation pour la transmission des utilisateurs

Configuration du Communication Arrangement

1. Créer le Communication Scenario

Le Communication Scenario définit les services outbound autorisés :

@EndUserText.label: 'RFC vers S/4HANA"
@ObjectModel.usageType.serviceQuality: #C
define abstract entity ZA_RFC_S4_SCENARIO
{
// Metadata pour Communication Scenario
}

Dans l’éditeur ADT pour les Communication Scenarios :

Communication Scenario: Z_RFC_S4HANA
Description: Communication RFC vers S/4HANA
Outbound Services:
├── RFC Service
│ ├── Service ID: Z_RFC_S4_SERVICE
│ ├── Service Type: RFC
│ └── Allowed Destinations: Z_S4HANA_RFC_*

2. Créer le Communication System

Le Communication System décrit le système cible :

┌──────────────────────────────────────────────────────────────┐
│ Communication System: Z_S4HANA_PROD │
├──────────────────────────────────────────────────────────────┤
│ General Data: │
│ ├── System ID: S4H │
│ ├── System Name: S/4HANA Production │
│ └── System Type: SAP System │
│ │
│ Technical Data (RFC): │
│ ├── Host: s4hana.company.com │
│ ├── Port: 443 (via Cloud Connector) │
│ ├── Virtual Host: s4hana-virtual:3300 │
│ └── Client: 100 │
│ │
│ User for Outbound Communication: │
│ └── Authentication: OAuth 2.0 / Basic / Certificate │
└──────────────────────────────────────────────────────────────┘

3. Activer le Communication Arrangement

L’Arrangement connecte le Scenario au System :

┌──────────────────────────────────────────────────────────────┐
│ Communication Arrangement: Z_RFC_S4HANA_PROD │
├──────────────────────────────────────────────────────────────┤
│ Communication Scenario: Z_RFC_S4HANA │
│ Communication System: Z_S4HANA_PROD │
│ │
│ Outbound Services: │
│ └── Z_RFC_S4_SERVICE: Active ✓ │
│ ├── Path: /sap/bc/srt/rfc/sap/ │
│ └── Authentication: OAuth2ClientCredentials │
└──────────────────────────────────────────────────────────────┘

Appel RFC via le Destination Service

Configurer la Destination

Dans le BTP Cockpit, la destination RFC est créée :

Name: S4HANA_RFC
Type: RFC
ProxyType: OnPremise (pour Cloud Connector)
RFC Properties:
├── jco.client.ashost: s4hana-virtual
├── jco.client.sysnr: 00
├── jco.client.client: 100
├── jco.client.lang: DE
├── jco.destination.pool_capacity: 10
└── jco.destination.peak_limit: 20
Authentication:
├── Type: BasicAuthentication
├── User: RFC_USER
└── Password: ********
Location ID: <Cloud Connector Location>

Générer le proxy RFC

Pour un appel RFC type-safe, un proxy est généré :

CLASS zcl_s4_material_proxy DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_material,
matnr TYPE c LENGTH 18,
maktx TYPE c LENGTH 40,
meins TYPE c LENGTH 3,
mtart TYPE c LENGTH 4,
END OF ty_material,
tt_materials TYPE STANDARD TABLE OF ty_material WITH EMPTY KEY.
METHODS constructor
RAISING cx_http_dest_provider_error.
METHODS get_material_details
IMPORTING iv_matnr TYPE matnr
RETURNING VALUE(rs_result) TYPE ty_material
RAISING cx_rfc_dest_provider_error
cx_communication_failure.
METHODS search_materials
IMPORTING iv_search_term TYPE string
RETURNING VALUE(rt_result) TYPE tt_materials
RAISING cx_rfc_dest_provider_error
cx_communication_failure.
PRIVATE SECTION.
DATA mo_destination TYPE REF TO if_rfc_destination.
ENDCLASS.
CLASS zcl_s4_material_proxy IMPLEMENTATION.
METHOD constructor.
" Récupérer la destination RFC du Destination Service
mo_destination = cl_rfc_destination_provider=>create_by_cloud_destination(
i_name = 'S4HANA_RFC' ).
ENDMETHOD.
METHOD get_material_details.
DATA: lv_matnr TYPE matnr,
ls_material TYPE ty_material.
lv_matnr = iv_matnr.
" Appel RFC via proxy
CALL FUNCTION 'BAPI_MATERIAL_GET_DETAIL"
DESTINATION mo_destination->get_destination_name( )
EXPORTING
material = lv_matnr
IMPORTING
material_general_data = ls_material
EXCEPTIONS
communication_failure = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_communication_failure
EXPORTING
textid = cx_communication_failure=>communication_failure.
ENDIF.
rs_result = ls_material.
ENDMETHOD.
METHOD search_materials.
DATA: lt_matnr_range TYPE RANGE OF matnr,
lt_materials TYPE tt_materials.
" Construire la plage de recherche
APPEND VALUE #(
sign = 'I"
option = 'CP"
low = |*{ iv_search_term }*| ) TO lt_matnr_range.
" Appel RFC
CALL FUNCTION 'BAPI_MATERIAL_GETLIST"
DESTINATION mo_destination->get_destination_name( )
TABLES
matnrselection = lt_matnr_range
matnrlist = lt_materials
EXCEPTIONS
communication_failure = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_communication_failure.
ENDIF.
rt_result = lt_materials.
ENDMETHOD.
ENDCLASS.

Utilisation dans RAP

Intégration du proxy RFC dans un RAP Business Object :

CLASS lhc_material DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_external_data FOR READ
IMPORTING keys FOR FUNCTION Material~getExternalData
RESULT result.
ENDCLASS.
CLASS lhc_material IMPLEMENTATION.
METHOD get_external_data.
TRY.
DATA(lo_proxy) = NEW zcl_s4_material_proxy( ).
LOOP AT keys INTO DATA(ls_key).
DATA(ls_material) = lo_proxy->get_material_details(
iv_matnr = ls_key-MaterialNumber ).
APPEND VALUE #(
%tky = ls_key-%tky
%param-Description = ls_material-maktx
%param-BaseUnit = ls_material-meins
%param-MaterialType = ls_material-mtart
) TO result.
ENDLOOP.
CATCH cx_http_dest_provider_error
cx_communication_failure INTO DATA(lx_error).
" Gestion des erreurs
LOOP AT keys INTO ls_key.
APPEND VALUE #(
%tky = ls_key-%tky
%fail = VALUE #( cause = if_abap_behv=>cause-unspecific )
) TO failed-material.
ENDLOOP.
ENDTRY.
ENDMETHOD.
ENDCLASS.

On-Premise vs. Cloud-to-Cloud

RFC Cloud-to-Cloud

Pour la communication purement Cloud, la configuration est plus simple :

CLASS zcl_cloud_rfc_client DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS call_remote_function
IMPORTING iv_param TYPE string
RETURNING VALUE(rv_result) TYPE string
RAISING cx_rfc_dest_provider_error.
ENDCLASS.
CLASS zcl_cloud_rfc_client IMPLEMENTATION.
METHOD call_remote_function.
" Destination Cloud directe (sans Cloud Connector)
DATA(lo_destination) = cl_rfc_destination_provider=>create_by_cloud_destination(
i_name = 'ABAP_CLOUD_SYSTEM_2' ).
" Appel RFC vers un autre système ABAP Cloud
CALL FUNCTION 'Z_REMOTE_FUNCTION"
DESTINATION lo_destination->get_destination_name( )
EXPORTING
iv_input = iv_param
IMPORTING
ev_output = rv_result
EXCEPTIONS
communication_failure = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_rfc_dest_provider_error.
ENDIF.
ENDMETHOD.
ENDCLASS.

Destination BTP pour Cloud-to-Cloud :

Name: ABAP_CLOUD_SYSTEM_2
Type: RFC
ProxyType: Internet
Authentication: OAuth2SAMLBearerAssertion
Token Service URL: https://other-abap-system.authentication.eu10.hana.ondemand.com/oauth/token
Additional Properties:
├── jco.client.ashost: other-abap-system-api.cfapps.eu10.hana.ondemand.com
├── jco.client.sysnr: 00
└── jco.client.client: 100

RFC On-Premise avec Cloud Connector

Pour les systèmes On-Premise, une configuration supplémentaire est requise dans le Cloud Connector :

┌──────────────────────────────────────────────────────────────┐
│ Cloud Connector Mapping │
├──────────────────────────────────────────────────────────────┤
│ Backend Type: ABAP System │
│ │
│ Virtual Host: s4hana-virtual │
│ Virtual Port: 3300 │
│ Internal Host: s4hana.internal.company.com │
│ Internal Port: 3300 │
│ │
│ Protocol: RFC │
│ Principal Type: X.509 Certificate (Recommandé) │
│ │
│ Resources: │
│ └── All (ou Function Modules spécifiques) │
└──────────────────────────────────────────────────────────────┘

Gestion des erreurs et Timeout

Classes d’exception

CLASS zcl_rfc_handler DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS execute_rfc
RETURNING VALUE(rv_result) TYPE string
RAISING zcx_rfc_error.
ENDCLASS.
CLASS zcl_rfc_handler IMPLEMENTATION.
METHOD execute_rfc.
TRY.
DATA(lo_destination) = cl_rfc_destination_provider=>create_by_cloud_destination(
i_name = 'S4HANA_RFC' ).
CATCH cx_rfc_dest_provider_error INTO DATA(lx_dest).
" Destination non trouvée ou mal configurée
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
previous = lx_dest
textid = zcx_rfc_error=>destination_not_found.
ENDTRY.
" Appel RFC avec gestion détaillée des erreurs
DATA lv_message TYPE c LENGTH 200.
CALL FUNCTION 'Z_REMOTE_FUNCTION"
DESTINATION lo_destination->get_destination_name( )
IMPORTING
ev_result = rv_result
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message
OTHERS = 3.
CASE sy-subrc.
WHEN 0.
" Succès
RETURN.
WHEN 1.
" Erreur réseau, timeout, système inaccessible
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>communication_failure
message = CONV #( lv_message ).
WHEN 2.
" Erreur ABAP dans le système cible (dump, exception)
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>system_failure
message = CONV #( lv_message ).
WHEN OTHERS.
" Erreur inconnue
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>unknown_error.
ENDCASE.
ENDMETHOD.
ENDCLASS.

Configuration du timeout

Les timeouts sont configurés dans la destination :

Name: S4HANA_RFC
Additional Properties:
├── jco.destination.expiration_time: 60000 " ms jusqu'au nettoyage de connexion
├── jco.destination.expiration_period: 60000 " Intervalle de vérification
├── jco.destination.max_get_time: 30000 " Temps d'attente max pour connexion
├── jco.client.cpic_timeout: 120 " Secondes pour l'appel RFC
└── jco.destination.peak_limit: 10 " Connexions parallèles max

Implémenter la logique de retry

CLASS zcl_rfc_retry_handler DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
CONSTANTS: c_max_retries TYPE i VALUE 3,
c_retry_delay TYPE i VALUE 2000. " ms
METHODS call_with_retry
IMPORTING iv_function TYPE rs38l_fnam
RETURNING VALUE(rv_result) TYPE string
RAISING zcx_rfc_error.
ENDCLASS.
CLASS zcl_rfc_retry_handler IMPLEMENTATION.
METHOD call_with_retry.
DATA: lv_retries TYPE i,
lv_message TYPE c LENGTH 200.
DATA(lo_destination) = cl_rfc_destination_provider=>create_by_cloud_destination(
i_name = 'S4HANA_RFC' ).
WHILE lv_retries < c_max_retries.
CALL FUNCTION iv_function
DESTINATION lo_destination->get_destination_name( )
IMPORTING
ev_result = rv_result
EXCEPTIONS
communication_failure = 1 MESSAGE lv_message
system_failure = 2 MESSAGE lv_message
OTHERS = 3.
CASE sy-subrc.
WHEN 0.
" Succès - retour immédiat
RETURN.
WHEN 1.
" Erreur de communication - retry pertinent
lv_retries = lv_retries + 1.
IF lv_retries < c_max_retries.
" Backoff exponentiel
DATA(lv_wait) = c_retry_delay * lv_retries.
cl_abap_session_context=>sleep( lv_wait ).
ENDIF.
WHEN 2.
" Erreur système - pas de retry car erreur logique
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>system_failure
message = CONV #( lv_message ).
WHEN OTHERS.
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING textid = zcx_rfc_error=>unknown_error.
ENDCASE.
ENDWHILE.
" Max retries atteint
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>max_retries_exceeded
message = |Max. { c_max_retries } tentatives atteintes : { lv_message }|.
ENDMETHOD.
ENDCLASS.

Monitoring et dépannage

Implémenter le logging

METHOD call_with_logging.
DATA lo_log TYPE REF TO if_bali_log.
TRY.
" Créer le log
lo_log = cl_bali_log=>create_with_header(
header = cl_bali_header_setter=>create(
object = 'Z_RFC_LOG"
subobject = 'RFC_CALLS"
external_id = |RFC_{ sy-datum }_{ sy-uzeit }| ) ).
" Entrée de démarrage
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_information
text = |Appel RFC démarré : { iv_function }| ) ).
DATA(lv_start) = utclong_current( ).
" Exécuter RFC
DATA(lv_result) = execute_rfc( iv_function ).
DATA(lv_end) = utclong_current( ).
DATA(lv_duration) = cl_abap_utclong=>diff(
high = lv_end
low = lv_start ).
" Logger le succès
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_status
text = |RFC réussi, durée : { lv_duration-second } secondes| ) ).
rv_result = lv_result.
CATCH zcx_rfc_error INTO DATA(lx_error).
" Logger l'erreur
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_error
text = |Erreur RFC : { lx_error->get_text( ) }| ) ).
RAISE EXCEPTION lx_error.
CLEANUP.
" Sauvegarder le log
IF lo_log IS BOUND.
cl_bali_log_db=>get_instance( )->save_log( log = lo_log ).
ENDIF.
ENDTRY.
ENDMETHOD.

Erreurs fréquentes et solutions

ErreurCauseSolution
COMMUNICATION_FAILURERéseau, timeoutVérifier Cloud Connector, augmenter timeout
SYSTEM_FAILUREDump dans le système cibleVérifier ST22 dans le système cible
RFC_ERROR_LOGON_FAILUREAuthentificationVérifier les credentials dans la destination
RFC_ERROR_SYSTEM_BUSYSurchargeAugmenter peak_limit, retry
RFC_ERROR_COMMUNICATIONProblème gatewayRedémarrer Cloud Connector

Bonnes pratiques

ThèmeRecommandation
Type de destinationDestination RFC uniquement pour les vrais appels RFC, pas pour HTTP
Connection PoolDéfinir pool_capacity et peak_limit appropriés
TimeoutTimeouts réalistes basés sur la durée attendue
Gestion des erreursToujours évaluer EXCEPTIONS, utiliser MESSAGE lv_message
RetryUniquement pour COMMUNICATION_FAILURE, pas pour SYSTEM_FAILURE
LoggingLogger tous les appels RFC pour le débogage
TestingDestinations séparées pour DEV/QA/PROD
SécuritéAutorisations RFC minimales dans le système cible

Sujets connexes