RFC in ABAP Cloud: Kommunikationsszenarien

kategorie
Integration
Veröffentlicht
autor
Johannes

Remote Function Call (RFC) ermöglicht die synchrone Kommunikation zwischen SAP-Systemen. In ABAP Cloud werden RFC-Verbindungen über Communication Arrangements und den Destination Service konfiguriert, um eine sichere und wartbare Integration zu gewährleisten.

RFC in ABAP Cloud vs. Klassisches ABAP

Die RFC-Kommunikation in ABAP Cloud unterscheidet sich grundlegend vom klassischen Ansatz:

AspektKlassisches ABAPABAP Cloud
KonfigurationSM59 RFC-DestinationCommunication Arrangement
AufrufCALL FUNCTION … DESTINATIONProxy-Klassen über IF_PROXY_CLIENT
AuthentifizierungIn SM59 hinterlegtOAuth2, Zertifikate, Principal Propagation
MonitoringSMGW, ST22SAP Cloud ALM, BTP Cockpit
FehlerbehandlungCOMMUNICATION_FAILUREException-Klassen
VerfügbarkeitAlle FuBasNur freigegebene Remote-enabled FuBas

Kommunikationsszenarien

Szenarien-Übersicht

Es gibt drei Hauptszenarien für RFC in ABAP Cloud:

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

Cloud-to-Cloud RFC

Bei Cloud-to-Cloud-Kommunikation verbinden sich zwei ABAP-Environment-Instanzen direkt:

Vorteile:

  • Keine zusätzliche Infrastruktur nötig
  • Automatische OAuth2-Authentifizierung
  • Hohe Verfügbarkeit durch BTP-Infrastruktur

Einschränkungen:

  • Nur remote-enabled Function Modules
  • Keine klassischen BAPIs (nur released APIs)

Cloud-to-On-Premise RFC

Für die Verbindung zu On-Premise-Systemen wird der SAP Cloud Connector benötigt:

Komponenten:

  • SAP Cloud Connector installiert im lokalen Netzwerk
  • Virtual Host Mapping für RFC-Gateway
  • Principal Propagation für Benutzerweiterleitung

Communication Arrangement einrichten

1. Communication Scenario anlegen

Das Communication Scenario definiert die erlaubten Outbound-Services:

@EndUserText.label: 'RFC zu S/4HANA'
@ObjectModel.usageType.serviceQuality: #C
define abstract entity ZA_RFC_S4_SCENARIO
{
// Metadata für Communication Scenario
}

Im ADT-Editor für Communication Scenarios:

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

2. Communication System anlegen

Das Communication System beschreibt das Zielsystem:

┌──────────────────────────────────────────────────────────────┐
│ Communication System: Z_S4HANA_PROD │
├──────────────────────────────────────────────────────────────┤
│ General Data: │
│ ├── System ID: S4H │
│ ├── System Name: S/4HANA Produktiv │
│ └── 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. Communication Arrangement aktivieren

Das Arrangement verbindet Scenario mit 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 │
└──────────────────────────────────────────────────────────────┘

RFC-Aufruf über Destination Service

Destination konfigurieren

Im BTP Cockpit wird die RFC-Destination erstellt:

Name: S4HANA_RFC
Type: RFC
ProxyType: OnPremise (für 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>

RFC-Proxy generieren

Für den typsicheren RFC-Aufruf wird ein Proxy generiert:

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.
" RFC-Destination vom Destination Service abrufen
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.
" RFC-Aufruf über 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.
" Suchbereich aufbauen
APPEND VALUE #(
sign = 'I'
option = 'CP'
low = |*{ iv_search_term }*| ) TO lt_matnr_range.
" RFC-Aufruf
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.

Verwendung in RAP

Integration des RFC-Proxys in einen 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).
" Fehlerbehandlung
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

Cloud-to-Cloud RFC

Bei reiner Cloud-Kommunikation ist die Konfiguration einfacher:

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.
" Direkte Cloud-Destination (ohne Cloud Connector)
DATA(lo_destination) = cl_rfc_destination_provider=>create_by_cloud_destination(
i_name = 'ABAP_CLOUD_SYSTEM_2' ).
" RFC-Aufruf zu anderem ABAP Cloud System
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.

BTP Destination für 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

On-Premise RFC mit Cloud Connector

Für On-Premise-Systeme ist zusätzliche Konfiguration im Cloud Connector erforderlich:

┌──────────────────────────────────────────────────────────────┐
│ 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 (Recommended) │
│ │
│ Resources: │
│ └── All (oder spezifische Function Modules) │
└──────────────────────────────────────────────────────────────┘

Fehlerbehandlung und Timeout

Exception-Klassen

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 nicht gefunden oder falsch konfiguriert
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
previous = lx_dest
textid = zcx_rfc_error=>destination_not_found.
ENDTRY.
" RFC-Aufruf mit detaillierter Fehlerbehandlung
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.
" Erfolg
RETURN.
WHEN 1.
" Netzwerkfehler, Timeout, System nicht erreichbar
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>communication_failure
message = CONV #( lv_message ).
WHEN 2.
" ABAP-Fehler im Zielsystem (Dump, Exception)
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>system_failure
message = CONV #( lv_message ).
WHEN OTHERS.
" Unbekannter Fehler
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>unknown_error.
ENDCASE.
ENDMETHOD.
ENDCLASS.

Timeout-Konfiguration

Timeouts werden in der Destination konfiguriert:

Name: S4HANA_RFC
Additional Properties:
├── jco.destination.expiration_time: 60000 " ms bis Connection-Cleanup
├── jco.destination.expiration_period: 60000 " Prüfintervall
├── jco.destination.max_get_time: 30000 " Max Wartezeit auf Connection
├── jco.client.cpic_timeout: 120 " Sekunden für RFC-Call
└── jco.destination.peak_limit: 10 " Max parallele Connections

Retry-Logik implementieren

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.
" Erfolg - sofort zurück
RETURN.
WHEN 1.
" Kommunikationsfehler - Retry sinnvoll
lv_retries = lv_retries + 1.
IF lv_retries < c_max_retries.
" Exponentielles Backoff
DATA(lv_wait) = c_retry_delay * lv_retries.
cl_abap_session_context=>sleep( lv_wait ).
ENDIF.
WHEN 2.
" Systemfehler - kein Retry, da Logikfehler
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 erreicht
RAISE EXCEPTION TYPE zcx_rfc_error
EXPORTING
textid = zcx_rfc_error=>max_retries_exceeded
message = |Max. { c_max_retries } Versuche erreicht: { lv_message }|.
ENDMETHOD.
ENDCLASS.

Monitoring und Troubleshooting

Logging implementieren

METHOD call_with_logging.
DATA lo_log TYPE REF TO if_bali_log.
TRY.
" Log erstellen
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 }| ) ).
" Start-Eintrag
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_information
text = |RFC-Aufruf gestartet: { iv_function }| ) ).
DATA(lv_start) = utclong_current( ).
" RFC ausführen
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 ).
" Erfolg loggen
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_status
text = |RFC erfolgreich, Dauer: { lv_duration-second } Sekunden| ) ).
rv_result = lv_result.
CATCH zcx_rfc_error INTO DATA(lx_error).
" Fehler loggen
lo_log->add_item(
item = cl_bali_free_text_setter=>create(
severity = if_bali_constants=>c_severity_error
text = |RFC-Fehler: { lx_error->get_text( ) }| ) ).
RAISE EXCEPTION lx_error.
CLEANUP.
" Log speichern
IF lo_log IS BOUND.
cl_bali_log_db=>get_instance( )->save_log( log = lo_log ).
ENDIF.
ENDTRY.
ENDMETHOD.

Häufige Fehler und Lösungen

FehlerUrsacheLösung
COMMUNICATION_FAILURENetzwerk, TimeoutCloud Connector prüfen, Timeout erhöhen
SYSTEM_FAILUREDump im ZielsystemST22 im Zielsystem prüfen
RFC_ERROR_LOGON_FAILUREAuthentifizierungCredentials in Destination prüfen
RFC_ERROR_SYSTEM_BUSYÜberlastungpeak_limit erhöhen, Retry
RFC_ERROR_COMMUNICATIONGateway-ProblemCloud Connector neu starten

Best Practices

ThemaEmpfehlung
Destination-TypRFC-Destination nur für echte RFC-Aufrufe, nicht für HTTP
Connection PoolAngemessene pool_capacity und peak_limit setzen
TimeoutRealistische Timeouts basierend auf erwarteter Laufzeit
FehlerbehandlungImmer EXCEPTIONS auswerten, MESSAGE lv_message nutzen
RetryNur bei COMMUNICATION_FAILURE, nicht bei SYSTEM_FAILURE
LoggingAlle RFC-Aufrufe für Debugging loggen
TestingSeparate Destinations für DEV/QA/PROD
SecurityMinimal notwendige RFC-Berechtigungen im Zielsystem

Weiterführende Themen