Application Development and Automation Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
Using class CL_ABAP_PARALLEL is a convenient way to mass process in parallel dialog work processes.  This can be especially powerful in a system with more dialog vs other types of work processes.  Due to limited documentation, there was a small learning curve when I first implemented this in an S4/HANA on-premise system on SAP_BASIS version 7.54.  I’m writing this blog to help others with their implementation of this class.

Important SAP Notes to consider

Setup overview

In this example there will be two local classes (to make it an easy copy/paste test).  The XSTRING data type is used to universally pass different kinds of data between the two classes.

  1. Local class MAIN

    1. The start and end point for the main logic outside of parallel processing



  2. Local class SINGLE_TASK

    1. Inherits from CL_ABAP_PARALLEL

    2. Contains logic to process one of the parallel task records at a time




Logic overview for class MAIN

  • Collect the necessary data for all the tasks

  • EXPORT all the task data and any shared task data

  • Create an instance of SINGLE_TASK passing parameters to control how many resources are used

    • See the Constructor parameters listed below



  • Call the RUN Method of SINGLE_TASK passing all the collected data for all tasks and receiving the results for all tasks

    • See the RUN Method parameters listed below, including the results/output structure details



  • IMPORT the task results to process them


Logic overview for class SINGLE_TASK

  • The DO Method is called once per task data record

  • IMPORT the single task record and any shared task data

  • Process the data as necessary

  • EXPORT the task results


Constructor parameters of CL_ABAP_PARALLEL

  • P_NUM_TASKS

    • If supplied, this will simply override P_NUM_PROCESSES



  • P_TIMEOUT

    • Amount of seconds the dialog process can run before automatically timing out



  • P_PERCENTAGE

    • Limits the number of simultaneous parallel processes by calculating the system allowable max parallel tasks across all application servers and reduces it according to the percentage.

    • For example, if there are two application servers with each having 100 as their max parallel task count and P_PERCENTAGE = 75; then the internal logic would limit the number of simultaneous parallel processes to 150

    • This value is ignored if P_NUM_PROCESSES is less than the % calculation



  • P_NUM_PROCESSES

    • Limits the number of simultaneous parallel processes

    • This is ignored if the number is greater than the allowable maximum parallel tasks across all application servers.

    • This value is also ignored whenever P_PERCENTAGE calculates to a lower number



  • P_LOCAL_SERVER

    • Optionally restrict the simultaneous parallel processes to only the current application server

    • This also impacts the internal calculations used for P_PERCENTAGE and P_NUM_PROCESSES




Notes: Class CL_SSI_DISPATCH is primarily controlling the server dispatch logic.  Function Module RS_ABAP_PARALLEL is used internally for executing the parallel tasks.

RUN Method parameters of CL_ABAP_PARALLEL

  • P_IN_TAB

    • Table of XSTRING values used as input for the parallel dialog tasks

    • One input row per dialog task



  • P_IN_ALL

    • Single XSTRING value

    • Shared record that’s available in all parallel dialog tasks



  • P_DEBUG

    • Debugging flag is used to skip the parallel framework and directly/sequentially call the DO Method



  • P_OUT_TAB

    • Table of XSTRING values

    • One output row per dialog task

    • Structure fields

      • RESULT - XSTRING of results populated within the DO Method

      • INDEX – Index of the table in P_IN_TAB

      • TIME – Seconds of runtime

      • MESSAGE – Error message for timeouts and other failures






Conclusion

Hopefully these details save you some time when implementing class CL_ABAP_PARALLEL yourself.  I’ve found this especially useful when programing a mass data correction utility and the timeframe to run it is limited.  I’ve attached an example program which is self contained by using local classes.  There are also some test classes for CL_ABAP_PARALLEL which provide useful examples.

 
REPORT zparallel_test.

CLASS main DEFINITION.

PUBLIC SECTION.

TYPES:
BEGIN OF shared_record,
process_mode TYPE c LENGTH 1,
END OF shared_record,

single_record TYPE scarr-carrid,

BEGIN OF task_result,
carrid TYPE scarr-carrid,
count TYPE i,
END OF task_result.

CLASS-METHODS process.

ENDCLASS.

CLASS single_task DEFINITION
INHERITING FROM cl_abap_parallel.

PUBLIC SECTION.

METHODS: do REDEFINITION.

ENDCLASS.

*This is the only statement outside of the classes
main=>process( ).

CLASS main IMPLEMENTATION.

METHOD process.

DATA: tasks_input TYPE cl_abap_parallel=>t_in_tab,
task_input_single TYPE xstring,
single_record TYPE single_record,
tasks_input_shared TYPE xstring,
shared_record TYPE shared_record,
task_result TYPE task_result.

shared_record-process_mode = 1.

* Since the process_mode value is shared across all tasks, store
* it in the shared variable (tasks_input_shared) instead of
* repeating it for every task input record (tasks_input)

* To be imported by SINGLE_TASK->DO
EXPORT buffer_task_shared = shared_record
TO DATA BUFFER tasks_input_shared.

* Get data to be processed. EXPORT each record and collect them all into
* table tasks_input.
SELECT
carrid
FROM scarr
INTO @single_record.

* To be imported by SINGLE_TASK->DO
EXPORT buffer_task = single_record TO DATA BUFFER task_input_single.
INSERT task_input_single INTO TABLE tasks_input.

ENDSELECT.

* Create the instance while configuring the resource usage
DATA(parallel) = NEW single_task(
* p_num_tasks = 8
* p_timeout = 200
* p_percentage = 50
* p_num_processes = 20
* p_local_server =
).

DATA(debug) = ' '.

* Perform the tasks in parallel
parallel->run(
EXPORTING
p_in_tab = tasks_input
p_in_all = tasks_input_shared
p_debug = debug
IMPORTING
p_out_tab = DATA(tasks_output)
).

LOOP AT tasks_output ASSIGNING FIELD-SYMBOL(<task_output_single>).

* Something went wrong, like a timeout, if the message has a value
IF <task_output_single>-message IS NOT INITIAL.
WRITE: / 'Task Error:', <task_output_single>-message.
ENDIF.

IF <task_output_single>-result IS NOT INITIAL.
* Exported from SINGLE_TASK->DO
IMPORT buffer_result = task_result
FROM DATA BUFFER <task_output_single>-result.

WRITE: / task_result-carrid, task_result-count.
ENDIF.

ENDLOOP.

ENDMETHOD.

ENDCLASS.

CLASS single_task IMPLEMENTATION.

METHOD do.

* I referenced the MAIN local class instead of using the data dictionary
* for the ease for copy/paste
DATA: shared_record TYPE main=>shared_record,
single_record TYPE main=>single_record,
task_result TYPE main=>task_result.

* Exported by MAIN->PROCCESS
IMPORT buffer_task_shared = shared_record FROM DATA BUFFER p_in_all.

* Exported by MAIN->PROCCESS
IMPORT buffer_task = single_record FROM DATA BUFFER p_in.

* Other shared values I like to include are a simulation/update flag
* and a level for the logging detail
CASE shared_record-process_mode.
WHEN '1'.

* Incredibly simplistic example which doesn't warrant parallel processing
SELECT
carrid,
COUNT( * )
FROM sflight
WHERE
carrid = @single_record
GROUP BY
carrid
INTO ( @task_result-carrid, @task_result-count ).

ENDSELECT.

WHEN '2'.
ENDCASE.

* To be imported by MAIN->PROCESS
EXPORT buffer_result = task_result TO DATA BUFFER p_out.

ENDMETHOD.

ENDCLASS.

 
8 Comments
Alparslan
Discoverer

Thank you for this useful blog.

michael_smithe5
Participant

@Dan_M , do you happen to have similar sample code for doing parallel database updates?  I am trying to determine if parallel processing will work for multiple calls to an update BAPI - if a call fails, I don't want to roll back all of the successful calls, only the call that failed.  If I use a wrapper FM that calls both the update BAPI and BAPI_TRANSACTION_COMMIT (or BAPI_TRANSACTION_ROLLBACK on failure), will parallel processing these commits cause a database deadlock?

Sandra_Rossi
Active Contributor

Thanks. In ABAP 7.58, I can see that CL_ABAP_PARALLEL documentation is provided:

  1. via its ABAP Doc comments,
  2. via this short introduction in the SAP Help Portal, Parallel Processing (*), and finally refers to the ABAP Doc comments.

There are also other features in CL_ABAP_PARALLEL:

  • EDIT June 27th, 2025: the methods *_INST were added in ABAP 7.54 but not downported on previous versions (2880858 - Changes to class CL_ABAP_PARALLEL - SAP for Me). The other methods, mentioned in the blog post, were downported to ABAP 7.50 (2791374 - Downport of class CL_ABAP_PARALLEL - SAP for Me).
  • The method RUN_INST can be used instead of RUN. It makes your custom code shorter by avoiding the serialization and deserialization of parameters which are done by CL_ABAP_PARALLEL. The principle of your custom code is to create directly an instance of CL_ABAP_PARALLEL, and each task is to be an instance of a custom class, with attributes for input and result data, implementing the interface IF_ABAP_PARALLEL, which is serializable (IF_SERIALIZABLE_OBJECT) and has the DO method. To start the parallelization, RUN_INST is to be run on the CL_ABAP_PARALLEL instance with the table of your "instance tasks" as input parameter. The result is a copy of your "instance tasks" which contain the results as instance attributes. One example is shown in the ABAP Doc comments of CL_ABAP_PARALLEL.
  • In case your custom application needs to get the results any time before the end of ALL tasks (for instance to achieve high performance in case of chained parallel processes), you  may use the methods FORK, JOIN and IS_COMPLETED. FORK starts one asynchronous task to start all the tasks. JOIN is to get the results of completed tasks, and so JOIN may be called several times till all tasks are completed.
  • There are also the methods FORK_INST and JOIN_INST (same principle as RUN_INST).
  • CONSTRUCTOR has the additional parameter P_ABORT_ON_ERROR to stop starting the remaining tasks if one has heavily failed (RFC communication error, short dump). Technically speaking, the remaining RFC tasks start but end immediately before calling the method DO.
  • CONSTRUCTOR has the additional parameter P_KEEPING_TASKS to not close the RFC connection after each task to manage buffered data. The concept is the same as RECEIVE RESULTS FROM FUNCTION funcname KEEPING TASK. You may close the connection explicitly via the method TERMINATE.
  • There is also the method START_INST_IN_BACKGROUND if you want to use bgRFC.
  • NB: don't use the public methods END_TASK and END_TASK_INT which are reserved to SAP for internal use.

(*) Full path in the SAP Help Portal: Home > SAP S/4HANA Cloud Public Edition > Developer Extensibility > Development in the ABAP Environment > Reuse Services and Libraries > ABAP Language > Parallel Processing)

Mickael_T
Participant

Hi @Sandra_Rossi , unfortunatly all those new methode *_INT are not available on 750, I did look on the downport note and this methods seems to appear later on...

Sandra_Rossi
Active Contributor

@Mickael_T Thanks. I edited my comment ("EDIT June 27th, 2025").

Mickael_T
Participant

So I'm starting using it on my test system, when trying to steer up a little bit,  I reach rapidly the maximum ressources available. Wich is not my real problem...

My issue is that the main work process stay stuck with status 'Back-End Session in PRIV Mode' and when I look at SM21 :

Dispatching changed due to resource usage (Resource=ES MEMORY, Limit=60.000 %, Curr.=87.709 %)
High resource usage ascertained (Resource=ES MEMORY, Limit=90.000 %, Curr.=96.089 %)
Snapshot 1 created; reason: Many (warn limit exceeded) ES Memory (96.089 %) allocated
Dispatching changed due to resource usage (Resource=ES MEMORY, Limit=60.000 %, Curr.=84.916 %)

So I understand that I overexeeded my ressources 😄 but on a real system how could I anticipate this ? And furthermore not stay stuck in PRIV mode T_T.

I tried to clear most of the data used by each tasks and not retrieving most of it to main process but still freezing.

Any ideas ?

@Sandra_Rossi maybe ? 🙂

 

Sandra_Rossi
Active Contributor

@Mickael_T Your active tasks are consuming too much memory. Let's say you have 1000 tasks but 10 are running at a time, these 10 tasks take all this memory, that's way too much. The principle of having many tasks is that each task takes little memory.

Sandra_Rossi
Active Contributor

For information, if CL_ABAP_PARALLEL is instantiated without P_TIMEOUT (default value 0), CL_ABAP_PARALLEL will calculate a timeout for RFC tasks which depends on the context where CL_ABAP_PARALLEL is instantiated:

  • If CL_ABAP_PARALLEL runs in dialog, the RFC tasks will use the high priority timeout i.e., the one defined by the profile parameter rdisp/scheduler/prio_high/max_runtime which is by default 660 seconds.
  • If CL_ABAP_PARALLEL runs in background, the RFC tasks will use the low priority timeout i.e., the one defined by the profile parameter rdisp/scheduler/prio_low/max_runtime which is by default unlimited (no timeout).

This is documented in this question, which concerns CL_ABAP_PARALLEL: Solved: TIMEOUT dump (11 min.) for RFC in low priority (ru... - SAP Community.