Introduction:
During my SAP ABAP development experience, I have worked on reports and interfaces that process large volumes of business data. One challenge I frequently noticed is that even well-written ABAP programs can become slow when they process thousands of records sequentially. As data volume grows, runtime increases significantly, affecting overall system performance and the user experience.
While exploring different performance optimization techniques, I came across the SPTA (SAP Parallel Task Administration) framework. What interested me most was that SAP already provides a standard mechanism to execute workloads in parallel instead of requiring developers to build a custom parallel processing solution from scratch. The framework takes care of distributing work packets, managing parallel tasks, utilizing available work processes, and collecting the results after processing is complete.
To better understand how SPTA works internally, I built a simple prototype instead of directly using a business scenario. The example generates random data, splits it into multiple work packets, processes each packet in parallel, and finally combines the results. This hands-on exercise helped me understand the complete flow of parallel processing and how the framework manages task execution behind the scenes.
In this blog, I will walk through the same example step by step, explain the key components involved, and share the learnings I gained while implementing the SPTA framework. I hope this practical approach helps anyone who is getting started with parallel processing in SAP ABAP.
What is SPTA Framework?
SPTA is a standard SAP framework designed to execute independent units of work in parallel. It internally manages:
Instead of manually creating asynchronous RFC tasks using STARTING NEW TASK, developers can leverage the SPTA framework to simplify implementation and improve maintainability.
Solution Overview-
The program follows the below execution flow:
The framework repeatedly executes these callback routines until all records are processed.
TYPE-POOLS: spta.
TYPES: BEGIN OF ty_final,
number TYPE char3,
index TYPE char3,
END OF ty_final.
TYPES: BEGIN OF ztest_random_data,
number TYPE char3,
index TYPE char3,
END OF ztest_random_data.
TYPES ztest_random_data_t TYPE STANDARD TABLE OF ztest_random_data
WITH EMPTY KEY.
DATA:
it_random TYPE ztest_random_data_t,
it_final TYPE STANDARD TABLE OF ty_final,
v_max_no_of_tasks TYPE syindex.
* Create random numbers
PERFORM f_create_random_no.
* Write random numbers before calling parallel processing
PERFORM f_write_random_rec.
"Fetch the server group
SELECT SINGLE classname
INTO @DATA(lv_server_grp)
FROM rzllitab
WHERE grouptype = 'S'.
IF sy-subrc NE 0.
RETURN.
ENDIF.
* Calling the function module to invoke parallel processing
* framwork
CALL FUNCTION 'SPTA_PARA_PROCESS_START_2'
EXPORTING
server_group = lv_server_grp
before_rfc_callback_form = 'BEFORE_RFC'
in_rfc_callback_form = 'IN_RFC'
after_rfc_callback_form = 'AFTER_RFC'
callback_prog = 'ZTEST_SPTA_FRAME_WORK'
CHANGING
user_param = it_random
EXCEPTIONS
invalid_server_group = 1
no_resources_available = 2
OTHERS = 3.
*&---------------------------------------------------------------------*
*& Form BEFORE_RFC
*&---------------------------------------------------------------------*
* In this routine work packets are prepared for parallel processing *
* also check the variable for downstream processing *
*----------------------------------------------------------------------*
FORM before_rfc
USING is_before_rfc_imp TYPE spta_t_before_rfc_imp
CHANGING es_before_rfc_exp TYPE spta_t_before_rfc_exp
it_rfcdata TYPE spta_t_indxtab
ct_failed_objects TYPE spta_t_failed_objects
et_objects_in_process TYPE spta_t_objects_in_process
it_data TYPE ztest_random_data_t.
DATA: l_counter TYPE i,
l_no_of_items TYPE i,
it_final TYPE ztest_random_data_t,
wa_data TYPE ztest_random_data.
* Create small work packets for parallel processing
* This is custom logic
l_no_of_items = 10. " One work packet will contain 10 records
LOOP AT it_data INTO wa_data.
* Read and move specified number of records
IF ( l_counter < l_no_of_items
AND wa_data IS NOT INITIAL ).
APPEND wa_data TO it_final.
DELETE it_data INDEX 1.
l_counter = l_counter + 1.
ELSE.
EXIT.
ENDIF.
ENDLOOP.
* Convert the input data into the INDX structure that is needed for the RFC
CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
EXPORTING
data = it_final
IMPORTING
indxtab = it_rfcdata.
* This is mandatory step
* inform task manager that an rfc can be started from the data compiled
IF it_final IS NOT INITIAL.
es_before_rfc_exp-start_rfc = 'X'.
ELSE.
CLEAR es_before_rfc_exp-start_rfc.
RETURN.
ENDIF.
ENDFORM. " BEFORE_RFC_CALLBACK_FORM
*&---------------------------------------------------------------------*
*& Form IN_RFC
*&---------------------------------------------------------------------*
* In this routine create own RFC enabled FM or write logic in this *
* routine *
*----------------------------------------------------------------------*
FORM in_rfc
USING is_in_rfc_imp TYPE spta_t_in_rfc_imp "#EC NEEDED
CHANGING es_in_rfc_exp TYPE spta_t_in_rfc_exp
it_rfcdata TYPE spta_t_indxtab.
DATA: it_final TYPE ztest_random_data_t.
* Decode the data from the INDX Structure into the process work list
CALL FUNCTION 'SPTA_INDX_PACKAGE_DECODE'
EXPORTING
indxtab = it_rfcdata
IMPORTING
data = it_final.
* Simple logic to sort data
SORT it_final BY number.
* Again Encode output data for AFTER_RFC form
CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
EXPORTING
data = it_final
IMPORTING
indxtab = it_rfcdata.
ENDFORM. "in_rfc
*&---------------------------------------------------------------------*
*& Form AFTER_RFC
*&---------------------------------------------------------------------*
* In this routine we have to collect date after parallel processing *
*----------------------------------------------------------------------*
FORM after_rfc
USING it_rfcdata TYPE spta_t_indxtab
if_rfcsubrc TYPE sy-subrc
if_rfcmsg TYPE spta_t_rfcmsg
it_objects_in_process TYPE spta_t_objects_in_process "#EC NEEDED
is_after_rfc_imp TYPE spta_t_after_rfc_imp "#EC NEEDED
CHANGING es_after_rfc_exp TYPE spta_t_after_rfc_exp "#EC NEEDED
cs_user_param TYPE ztest_random_data_t.
DATA: wa_final TYPE ztest_random_data.
* Decode RFC output data and add RFC-results to global data
CALL FUNCTION 'SPTA_INDX_PACKAGE_DECODE'
EXPORTING
indxtab = it_rfcdata
IMPORTING
data = it_final.
* After parallel processing write all the records
LOOP AT it_final INTO wa_final.
WRITE:/ wa_final-number, 10 wa_final-index.
CLEAR wa_final.
ENDLOOP.
WRITE: sy-uline.
ENDFORM. "after_rfc
*&---------------------------------------------------------------------*
*& Form F_CREATE_RANDOM_NO
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM f_create_random_no.
DATA: lcl_random TYPE REF TO cl_abap_random_int,
l_index TYPE sytabix,
lwa_data TYPE ztest_random_data,
l_min TYPE i,
l_max TYPE i.
l_min = 10.
l_max = 90.
TRY.
lcl_random = cl_abap_random_int=>create( min = l_min
max = l_max ).
CATCH cx_abap_random.
ENDTRY.
DO 100 TIMES.
* Get the Random Number:
lwa_data-number = lcl_random->get_next( ).
l_index = l_index + 1.
lwa_data-index = l_index.
APPEND lwa_data TO it_random.
ENDDO.
ENDFORM. " F_CREATE_RANDOM_NO
*&---------------------------------------------------------------------*
*& Form F_WRITE_RANDOM_REC
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* --> p1 text
* <-- p2 text
*----------------------------------------------------------------------*
FORM f_write_random_rec.
DATA: wa_final TYPE ztest_random_data.
WRITE:/ 'Before parallel processing start'.
LOOP AT it_random INTO wa_final.
WRITE:/ wa_final-number, 10 wa_final-index.
CLEAR wa_final.
ENDLOOP.
WRITE:/ 'After end parallel processing'.
ENDFORM. " F_WRITE_RANDOM_REC*&---------------------------------------------------------------------*Generate Sample Data-
FORM f_create_random_no.
DATA: lcl_random TYPE REF TO cl_abap_random_int,
l_index TYPE sytabix,
lwa_data TYPE ztest_random_data,
l_min TYPE i,
l_max TYPE i.
l_min = 10.
l_max = 90.
TRY.
lcl_random = cl_abap_random_int=>create( min = l_min
max = l_max ).
CATCH cx_abap_random.
ENDTRY.
DO 100 TIMES.
* Get the Random Number:
lwa_data-number = lcl_random->get_next( ).
l_index = l_index + 1.
lwa_data-index = l_index.
APPEND lwa_data TO it_random.
ENDDO.
ENDFORM. " F_CREATE_RANDOM_NOThis routine generates 100 random records and stores them in IT_RANDOM.
Example:
NUMBER INDEX
------------------------
45 1
72 2
18 3
63 4
At this point, all records are available for processing.
Determine Server Group-
"Fetch the server group
SELECT SINGLE classname
INTO @DATA(lv_server_grp)
FROM rzllitab
WHERE grouptype = 'S'.
IF sy-subrc NE 0.
RETURN.
ENDIF.The SPTA framework requires an RFC Server Group.
Server groups are configured in transaction: RZ12
The framework uses this server group to determine where parallel tasks can run.
Start the SPTA Framework-
* Calling the function module to invoke parallel processing
* framwork
CALL FUNCTION 'SPTA_PARA_PROCESS_START_2'
EXPORTING
server_group = lv_server_grp
before_rfc_callback_form = 'BEFORE_RFC'
in_rfc_callback_form = 'IN_RFC'
after_rfc_callback_form = 'AFTER_RFC'
callback_prog = 'ZTEST_SPTA_FRAME_WORK'
CHANGING
user_param = it_random
EXCEPTIONS
invalid_server_group = 1
no_resources_available = 2
OTHERS = 3.This is the entry point of the framework.
The entire table IT_RANDOM is passed through:
user_param = it_random
Internally, SPTA passes this table to BEFORE_RFC, where work packets are created.
The framework then repeatedly executes:
Until all records have been processed.
BEFORE_RFC: Create Work Packets-
This callback prepares the data packets that will be processed in parallel.
*&---------------------------------------------------------------------*
*& Form BEFORE_RFC
*&---------------------------------------------------------------------*
* In this routine work packets are prepared for parallel processing *
* also check the variable for downstream processing *
*----------------------------------------------------------------------*
FORM before_rfc
USING is_before_rfc_imp TYPE spta_t_before_rfc_imp
CHANGING es_before_rfc_exp TYPE spta_t_before_rfc_exp
it_rfcdata TYPE spta_t_indxtab
ct_failed_objects TYPE spta_t_failed_objects
et_objects_in_process TYPE spta_t_objects_in_process
it_data TYPE ztest_random_data_t.
DATA: l_counter TYPE i,
l_no_of_items TYPE i,
it_final TYPE ztest_random_data_t,
wa_data TYPE ztest_random_data.
* Create small work packets for parallel processing
* This is custom logic
l_no_of_items = 10. " One work packet will contain 10 records
LOOP AT it_data INTO wa_data.
* Read and move specified number of records
IF ( l_counter < l_no_of_items
AND wa_data IS NOT INITIAL ).
APPEND wa_data TO it_final.
DELETE it_data INDEX 1.
l_counter = l_counter + 1.
ELSE.
EXIT.
ENDIF.
ENDLOOP.
* Convert the input data into the INDX structure that is needed for the RFC
CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
EXPORTING
data = it_final
IMPORTING
indxtab = it_rfcdata.
* This is mandatory step
* inform task manager that an rfc can be started from the data compiled
IF it_final IS NOT INITIAL.
es_before_rfc_exp-start_rfc = 'X'.
ELSE.
CLEAR es_before_rfc_exp-start_rfc.
RETURN.
ENDIF.
ENDFORM. " BEFORE_RFC_CALLBACK_FORM Each work packet contains 10 records.
For 100 records:
Packet 1 -> Records 1 to 10
Packet 2 -> Records 11 to 20
Packet 3 -> Records 21 to 30
...
Packet 10 -> Records 91 to 100
The framework passes the remaining data in IT_DATA.
This logic:
Example:
Before:
IT_DATA = 100 records
After first packet:
IT_FINAL = 10 records
IT_DATA = 90 records
Convert Packet into RFC Format-
SPTA transfers data between work processes using INDX structures.
This function serializes the packet into a format suitable for RFC communication.
Signal Framework to Start Processing-
This informs the framework that a work packet is ready, and a new RFC task can be started.
IN_RFC: Execute Business Logic-
This routine runs in a separate work process.
*&---------------------------------------------------------------------*
*& Form IN_RFC
*&---------------------------------------------------------------------*
* In this routine create own RFC enabled FM or write logic in this *
* routine *
*----------------------------------------------------------------------*
FORM in_rfc
USING is_in_rfc_imp TYPE spta_t_in_rfc_imp "#EC NEEDED
CHANGING es_in_rfc_exp TYPE spta_t_in_rfc_exp
it_rfcdata TYPE spta_t_indxtab.
DATA: it_final TYPE ztest_random_data_t.
* Decode the data from the INDX Structure into the process work list
CALL FUNCTION 'SPTA_INDX_PACKAGE_DECODE'
EXPORTING
indxtab = it_rfcdata
IMPORTING
data = it_final.
* Simple logic to sort data
SORT it_final BY number.
* Again Encode output data for AFTER_RFC form
CALL FUNCTION 'SPTA_INDX_PACKAGE_ENCODE'
EXPORTING
data = it_final
IMPORTING
indxtab = it_rfcdata.
ENDFORM. "in_rfcDecode Packet-
The encoded packet is converted back into an internal table -> process data -> then packet is sorted by the random number.
Encode Results-
The processed data is encoded again so that it can be returned to the caller.
AFTER_RFC: Collect Results-
Once a parallel task is complete, the framework invokes AFTER_RFC.
*&---------------------------------------------------------------------*
*& Form AFTER_RFC
*&---------------------------------------------------------------------*
* In this routine we have to collect date after parallel processing *
*----------------------------------------------------------------------*
FORM after_rfc
USING it_rfcdata TYPE spta_t_indxtab
if_rfcsubrc TYPE sy-subrc
if_rfcmsg TYPE spta_t_rfcmsg
it_objects_in_process TYPE spta_t_objects_in_process "#EC NEEDED
is_after_rfc_imp TYPE spta_t_after_rfc_imp "#EC NEEDED
CHANGING es_after_rfc_exp TYPE spta_t_after_rfc_exp "#EC NEEDED
cs_user_param TYPE ztest_random_data_t.
DATA: wa_final TYPE ztest_random_data.
* Decode RFC output data and add RFC-results to global data
CALL FUNCTION 'SPTA_INDX_PACKAGE_DECODE'
EXPORTING
indxtab = it_rfcdata
IMPORTING
data = it_final.
* After parallel processing write all the records
LOOP AT it_final INTO wa_final.
WRITE:/ wa_final-number, 10 wa_final-index.
CLEAR wa_final.
ENDLOOP.
WRITE: sy-uline.
ENDFORM. "after_rfc Decode Returned Data-
The processed packet is reconstructed -> The processed records are displayed.
Example-
Suppose the program generates:
| 45 1 81 2 23 3 67 4 ... |
The framework creates: Packet 1 -> 10 Records These packets are distributed among available work processes: WP1 -> Packet 1 |
Each work process executes the logic inside IN_RFC independently and returns the results through AFTER_RFC.
Let’s execute and see--
Advantages of SPTA Framework-
Conclusion-
The SPTA framework provides a robust and SAP-standard approach for implementing parallel processing in ABAP. By splitting large datasets into smaller work packets and distributing them across multiple work processes, developers can significantly improve application performance while keeping the implementation manageable.
In this example, we generated random data, divided it into packets of 10 records, processed those packets in parallel, and collected the results using the three core callback routines:
For real-world scenarios involving mass data processing, SPTA offers a scalable and efficient solution that aligns with SAP development best practices.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 16 | |
| 7 | |
| 6 | |
| 6 | |
| 4 | |
| 4 | |
| 3 | |
| 2 | |
| 2 | |
| 2 |