
ABAP Quick - Wait for task
Today a tip for asynchronous processing or if you want to put processing in a separate task in special situations. What happens afterwards?
Table of contents
Have you ever asked yourself whether you can wait for a process after moving it to an asynchronous task? In some situations there is no other way, because the coding position does not allow a commit or prescribes it. In today's example we want to show you how you can wait for the process and then continue working on this data.
Function module
To prepare, we need a function module that carries out the task and is used to understand it. This gets a few import parameters to represent a dummy interface. We also wait 5 seconds in the function block before processing continues in order to simulate long processing.
FUNCTION Z_60BS_TEST_ASYNC_FUNCTION
IMPORTING
VALUE(ID_FLAG) TYPE ABAP_BOOLEAN
VALUE(ID_USER) TYPE SYUNAME
VALUE(IT_DATA) TYPE STRING_TABLE.
WAIT UP TO 5 SECONDS.
ENDFUNCTION.
Don't forget that the function module must be RFC-capable so that it can be started in a separate task. Here is an excerpt from Eclipse, here you can set this via the "Properties" view.
Test setup
For the validation of the result, we rely on a time measurement to determine whether the process is waiting for our parallel task. Before calling the function module, we start the timer and note the start time. Next, we call the function module with the addition STARTING NEW TASK to start the process asynchronously in a new task. At the end we calculate the difference and look at the result. The function module should run for 5 seconds before it terminates.
DATA:
ld_task TYPE char32 VALUE 'TASK_01'.
DATA(lo_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(ld_start) = lo_timer->get_runtime( ).
CALL FUNCTION 'Z_BS_TEST_ASYNC_FUNCTION'
STARTING NEW TASK ld_task
EXPORTING
id_flag = abap_true
id_user = sy-uname
it_data = VALUE string_table( ( `A` ) ( `B` ) ( `C` ) ).
out->write( |Process completed: { lo_timer->get_runtime( ) - ld_start }| ).
Processing ends after a few milliseconds, and the module is ended in a separate task. So if we wait for the end and possible data from the function module, then we have no chance to react.
Solution
In this case, what can you do to respond to the outcome? In the first step, we have to add a callback to the function module so that we can see in our current processing when the module is finished. To do this, we use the addition CALLING ... ON END OF TASK and specify a method that is called in our class at the end of processing.
CALL FUNCTION 'Z_BS_TEST_ASYNC_FUNCTION'
STARTING NEW TASK ld_task
CALLING finished ON END OF TASK
EXPORTING
id_flag = abap_true
id_user = sy-uname
it_data = VALUE string_table( ( `A` ) ( `B` ) ( `C` ) ).
The method requires an input parameter with the name P_TASK, this contains the value that you gave when calling it, so that you can identify the returning process.
METHODS:
finished IMPORTING p_task TYPE char32.
So we know that the process will report back when the processing is done. What is still required now is to keep processing until the feedback has been received from the function module. A WAIT with an addition comes into play. In this case there is a member variable in the class that we set as soon as the task has ended.
WAIT FOR ASYNCHRONOUS TASKS UNTIL md_finished = abap_true.
If we now run the class again, the result will be different. The report waits approx. 5 seconds before the measurement stops and further processing is resumed.
Example
Here again the complete example of the console application with the corresponding implementations for the example.
CLASS zcl_test_async_start DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES: if_oo_adt_classrun.
DATA:
md_finished TYPE abap_bool.
METHODS:
finished
IMPORTING
p_task TYPE char32.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_test_async_start IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA:
ld_task TYPE char32 VALUE 'TASK_01'.
DATA(lo_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(ld_start) = lo_timer->get_runtime( ).
CALL FUNCTION 'Z_BS_TEST_ASYNC_FUNCTION'
STARTING NEW TASK ld_task
CALLING finished ON END OF TASK
EXPORTING
id_flag = abap_true
id_user = sy-uname
it_data = VALUE string_table( ( `A` ) ( `B` ) ( `C` ) ).
WAIT FOR ASYNCHRONOUS TASKS UNTIL md_finished = abap_true.
out->write( |Process completed: { lo_timer->get_runtime( ) - ld_start }| ).
ENDMETHOD.
METHOD finished.
md_finished = abap_true.
ENDMETHOD.
ENDCLASS.
Conclusion
So how do you wait for the process to complete? With our example this should no longer be a problem and you can experiment a little more with it. What about a commit in the function block and how does our waiting program react to it? Certainly also a couple of exciting questions.