In this article, we take a closer look at the Background Process Framework, also known as bgPF. What does it do? What’s its use in ABAP Cloud and RAP applications?

Then we’ll look at a concrete example I’ve prepared.

First of all, I encourage you to read my article RAP application with BAPI – Clean Core objective – section “ABAP RAP, in the context of ABAP CLOUD” if you’d like to understand a little more about ABAP Cloud concepts and in particular the concepts of LUW and Controlled LUW (how and when data should be saved in the system).

Technical prerequisites: BTP, ABAP environment (via Trial BTP for example, which is done here), S/4 Hana Cloud, S/4 Hana On Premise / Private Cloud releases greater than or equal to 2023.

bgPF c’est quoi ?

Simply put, bgPF offers the functionality to reliably execute processing steps in the background for the various applications being developed. It’s a simple, easy-to-use feature for reliably executing time-consuming ABAP methods asynchronously.

Also, using bgPF is useful if you need to trigger a feature in a session other than the current one, for example because the feature you want to call performs a database commit while you’re still in the interaction phase (see my article cited above if you need more details on the different phases in ABAP Cloud).

Finally, bgPF can also be seen as the successor to tRFC and qRFC.

In this shema, we can see how bgPF works:

  1. The application creates a bgPF instance (see below how to do this)
  2. bgPF execution is put “on hold
  3. Once the COMMIT in the application has been performed, the bgPF(s) execute(s).

Technical documentation bgPF: https://help.sap.com/docs/abap-cloud/abap-concepts/background-processing-framework

Controlled LUW technical documentation: https://help.sap.com/docs/abap-cloud/abap-concepts/controlled-sap-luw

The introduction to bgPF from which I have taken the information: https://community.sap.com/t5/technology-blogs-by-sap/introducing-the-background-processing-framework/ba-p/13579056

Test cases

For this example, I had the choice of :

either the case of a process that needs to be run in the background, as it consumes resources and time
Or the case where the use of bgPF is necessary to maintain transactional consistency. As a reminder, “transational consistency” means respecting the rules of LUW within the Cloud in ABAP, i.e. :

1/ An interaction phase, in which all data that has been modified, created or deleted is buffered and validated.

2/ A save phase where no more errors are expected to occur, and where the data is stored persistently in the database.

This video (from minute 41, explains the concept very well) :

As there are already examples on the Internet of the use of bgPF for the first case, we’ll look at the 2nd case: bgPF in the context of “transactional consistency”.

Example description

Here, we’re going to create a RAP application, which must call a POST API (i.e. create data) in an external system when a new line is created (not in the case of modification or deletion, only in the case of creation).

Note that here I’m going to use a dummy POST API call that simply returns an ID without doing anything special, but this is just an example (API used: https://www.toptal.com/developers/postbin/ ).

This case works for all cases where there is a remote connection (RFC, API, etc…) with the aim of modifying, deleting or creating data.

Here are the issues:

1/ If you follow the strict “controlled LUW” rules when creating a RAP application (identified by the “strict(2)” statement during behavior implementation, which I always recommend (we’ll come back to this below), it’s impossible to call an API via an HTTP client during the save phase.

Why not? Because establishing an HTTP connection performs an implicit database commit. This is forbidden, because if you have started to write information to the database, which is the aim of the save phase, then the data will be saved in the database, even though we are not immune to any errors later on in the save process.

2/ Technically, we could call this API POST in the interaction phase.
In fact, this is the best way to obtain data (do a GET).
Indeed, as it is forbidden to write data in the interaction phase, it doesn’t matter if there are “implicit database commits”, as no data will be saved in the database.
BUT here, it’s not just a question of reading, but also of writing data. So it makes no sense to create data during the interaction phase: what if there’s an error during data validation, for example? Then we’d never get to the save phase, and we’d already have written the data to the remote system without fully completing the process.

Solution: In this case, we need to create a process that will be called in another session, during the save phase, so as not to create a database commit. We’ll therefore use the bgPF during the save phase.

Test case implementation

1/ Creating a basic RAP application

Here I’ve created a basic RAP application from scratch, going from a Z table to the creation of CDS and Behaviors.

I won’t go into the details of this creation, as all you have to do is follow this simple tutorial: https://developers.sap.com/group.abap-build-fiori-element-rap.html

Here are the objects generated to create a travel management application.

However, we’ll have to modify this application later to add the bgPF call, and I’ll come back to this later.

2/ Creating the bgPF class

There are 2 options:

  • Either an interface that respects transactional consistency rules within the bgPF => if_bgmc_op_single
  • or an “uncontrolled” interface => if_bgmc_op_single_tx_uncontr

As the sole purpose of this class will be to call a POST API, I’ll use the if_bgmc_op_single_tx_uncontr interface.

CLASS zbgpf DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
  INTERFACES if_bgmc_op_single_tx_uncontr.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zbgpf IMPLEMENTATION.

  METHOD if_bgmc_op_single_tx_uncontr~execute.

    TRY.
        "DUMMY HTTP POST REQUEST
        DATA(dest) = cl_http_destination_provider=>create_by_url( 'https://www.toptal.com/developers/postbin/1715537134683-0620718607679' ).
        DATA(client) = cl_web_http_client_manager=>create_by_http_destination( dest ).
        DATA(req) = client->get_http_request(  ).
        DATA(post) = client->execute( if_web_http_client=>post )->get_text(  ).
        client->close(  ).
      CATCH cx_root INTO DATA(error). "Catch all exceptions
    ENDTRY.

  ENDMETHOD.

ENDCLASS.

In the if_bgmc_op_single_tx_uncontr~execute method, I’ve written the HTTP client creation followed by the API POST call, which must be made in the background.

3/ Modify the behavior definition to set the save phase to “unmanaged save” and thus manage the save phase autonomously.

Remove the “persistent table” statement and create “unmanaged save”, which then generates a method for managing the save itself (as you can see here, we’re in strict(2) mode):

4/ Implementing the Save method

  METHOD save_modified.

DATA: ls_ZTEST_TABLE_CRT TYPE ZTEST_TABLE_CRT.

1/ On boucle sur les données modifiées pour modifier les lignes de la table
LOOP AT update-zr_test_table_crt INTO data(ls_update).
ls_ZTEST_TABLE_CRT = CORRESPONDING #( ls_update MAPPING FROM
ENTITY ).
MODIFY ZTEST_TABLE_CRT FROM @ls_ZTEST_TABLE_CRT.
ENDLOOP.

2/ On boucle sur les données supprimées pour supprimer les lignes de la table
LOOP AT delete-zr_test_table_crt INTO data(ls_delete).
ls_ZTEST_TABLE_CRT = CORRESPONDING #( ls_delete MAPPING FROM
ENTITY ).
DELETE ZTEST_TABLE_CRT FROM @ls_ZTEST_TABLE_CRT.
ENDLOOP.

3/ On boucle sur les données à créer ET on appelle le bgPF créé plus haut
LOOP AT create-zr_test_table_crt INTO data(ls_create).
ls_ZTEST_TABLE_CRT = CORRESPONDING #( ls_create MAPPING FROM
ENTITY ).
MODIFY ZTEST_TABLE_CRT FROM @ls_ZTEST_TABLE_CRT.
* On instancie la classe pour le bgPF
    DATA(new) = NEW zbgpf(  ).
    DATA background_process TYPE REF TO if_bgmc_process_single_op.
    TRY.
* On crée le nouveau process qui devra être lancé en arrière plan
        background_process = cl_bgmc_process_factory=>get_default(  )->create(  ).
* On appelle l'opération qui devra être executée
        background_process->set_operation_tx_uncontrolled( new ).
* On sauvegarde pour exécution après COMMIT.
        background_process->save_for_execution(  ).
* COMMIT WORK. "Pas nécessaire dans le cas d'une application RAP car le framework le gère.
      CATCH cx_bgmc INTO DATA(exception).
    ENDTRY.
ENDLOOP.

  ENDMETHOD.

Since this is a RAP application, there’s no need for an explicit COMMIT, since everything is handled by the RAP framework.

This RAP application allows you to call a POST API in the background during the save phase. This ensures compliance with transactional consistency in ABAP Cloud.

Debug

I set a breakpoint in the save phase to see what happens.

I launch the application in preview and create a new entry:

When I save the creation, I arrive in the previously created save method:

As there is no update or deletion, only creation, the newly created instance in the buffer is processed directly:

As seen above, this is where the background process is created and queued.

As you can see, the bgPF has not yet been called, even at the end of the method, since the COMMIT has not yet taken place:

Une fois le COMMIT atteint lors du processus du framework RAP, on arrive bien au bgPF :

As explained above, this is just a test API POST call that returns some kind of ID to indicate that the call was successful, but it could have been, for example, the creation of the line created in the Fiori application in a remote system:

We return to the Fiori application and see the newly created line

Conclusion

Now you know what the bgPF is for, how to use it and what the various use cases are.

Note that it’s important to set up a monitoring system to validate that everything has run smoothly in the background. SAP offers standard solutions for this.

Github repository : https://github.com/Abapeur/bgPF