Parallelization in Web UI

PART 3


AJAX (… continued)

Limits of a stateful application

Now let us place two samples from above onto the same page:

/wp-content/uploads/2015/12/image017_849946.png                        

You will notice down that the response time is significantly higher than before. In the HTTPWatch trace you will see that both AJAX calls are triggered simultaneously, but the first is finished within about 3 seconds, and the second one took significantly longer.

/wp-content/uploads/2015/12/image018_849959.png

This is caused by increased wait time. As long as our application is totally stateful, we are trying to access the same user context. In case of several requests, they have to wait till the context is unlocked with one work process, i.e. when the current task is finished.

/wp-content/uploads/2015/12/image019_849960.png

On SAP instance level we see that our session is waiting for a certain work process to be released.


/wp-content/uploads/2015/12/image020_849961.png   /wp-content/uploads/2015/12/image021_849962.png

     

This is a main limitation of stateful SAP applications. Stateful requests cannot be processed in parallel, even if they operate with different objects. Whenever the request is processed by Dialog Work Process (DIA), the whole user context get’s locked.  Considering this limitation, by implementing AJAX calls in stateful SAP applications, you can increase usability of your solution, but hardly performance (unless you are using just one call). 

1.     aRFC or Strength of Value Nodes


The last topic that I would like to review here is how asynchronous RFC can help you to speed up processing of requests from WebUI. You may wish to use this very old technique in order to speed up opening of the overview pages or customer fact sheets, or similar applications. In the standard, this technique is not used by intention and therefore you need to implement it on your own. Furthermore the standard, in most of the cases, is using Model Nodes, which provide a continuous processing from UI/BSP level down to GENIL/API level, and it’s not possible to break down this program execution flow easily.

From my prospective there are two ways how or where the parallelization through asynchronous RFC can be implemented:

The first way is to parallelize processing on GENIL/API level for each individual object. In this case you need to redefine GENIL implementation classes up to your needs. But even though it’s not always possible due to limitations of API functionality. So finally this approach does not look very attractive, however may still exist.

The second way is to make a parallelization through asynchronous RFC on WEBUI level, e.g. on the level of assignment blocks. However in this case we need to break down the standard processing flow mentioned above. This cannot be easily done for Model Nodes, but the Value Nodes do not have such limitation as they just need the data at certain time and certain place (e.g. ON_NEW_FOCUS), and they do not care how this data is retrieved.

Below we will review such a case, based on the partner overview page: BP_HEAD/BPHEADOverview.

Below two diagrams will help you to understand how the concept can be implemented and what is the difference comparing with the standard processing.

Standard program flow

/wp-content/uploads/2015/12/image022_849963.png

Processing of the overview page stats from DO_REQUEST and is followed by processing of individual views sequentially in the loop (BIND_VIEW). When the context of the view gets initialized normally ON_NEW_FOCUS event is triggered and at this point the data will be read for each context node that is assigned.

Program flow implementing asynchronous RFC processing

/wp-content/uploads/2015/12/image023_849964.png

One can see that the general timeline is shorter due to asynchronous RFC retrieving the data, executed in parallel. This of course requires more system resources, primarily work processes.

Processing of the overview page starts from DO_REQUEST, however at certain point, we split data extraction for our assignment blocks or context nodes. At this point you need to read the personalization to see which assignment blocks are opened and will be processed. It can be done in the method DO_CONFIG_DETERMINATION of your overview page. To get the assigned blocks, you can use the following coding.

        ” get configuration in xml language
          me
->configuration_descr->get_config_data(
            receiving  rv_result
= lv_config_xml
           
exceptions foreign_lock = 1
                       config_not_found
= 2 ).
         
if sysubrc = 2.
           
exit.
         
endif.
 
         
” transform configuration xml into table definition
         
call method cl_bsp_dlc_config_ovw=>conv_xml_to_data(
           
exporting
              iv_xml 
= lv_config_xml
           
importing
              rt_data
= ls_assgnm_xml ).
 
         
” get relevant data from config XML
          lt_view_area
= ls_assgnm_xmlviews.

Once you know the assignment blocks, you should launch respective functions asynchronously. It is worth to write a general helper class in order to manage this process. You can also develop some customizing tables for your needs.

        data: lr_rfc_man    type ref to zdmsh_ab_rfc_manager.
 

          
” Get RFC Manager
          lr_rfc_man
= zdmsh_ab_rfc_manager=>get_instance( ).
 
         
if lr_rfc_man is bound and
             lr_partner
is bound.
 
           
” Set Current Partner
            lr_rfc_man
->set_partner( lr_partner ).
 
           
” Register Necessary Blocks
            lr_rfc_man
->process_viewarea( it_viewarea = lt_view_area ).
 
           
Start Function
            lr_rfc_man
->start_functions( ).
 
 

        endif.

After this the process continues as normal.

Later at each relevant ON_NEW_FOCUS event you need to get the results of the executed functions and provide it to the respective context nodes.


 
     
data: lr_rfc_man     type ref to zdmsh_ab_rfc_manager.
     
data: lt_c_hist      type crmt_bupa_il_changedoc_t.
     
data: ls_c_hist      type crmt_bupa_il_changedoc.
     
data: lr_table_line  type ref to crmt_bupa_il_changedoc.
     
data: lr_wrapper     type ref to cl_bsp_wd_collection_wrapper.
     
data: lr_valuenode   type ref to cl_bsp_wd_value_node.
 
 
     
” Get RFC Manager
      lr_rfc_man
= zdmsh_ab_rfc_manager=>get_instance( ).
 
     
” Wait Till Our Block Is Done
      lr_rfc_man
->wait_for_task( iv_application = ‘ZDMSH_RFC_TEST’
                                 iv_view       
= ‘ChangeHistory’ ).
 
     
” Get Data
     
call method lr_rfc_man->get_change_history
       
importing
          et_change_history
= lt_c_hist.
 
     
” Fill Context Node
      lr_wrapper
= get_collection_wrapper( ).
 
     
if lr_wrapper is bound.
 
        lr_wrapper
->clear( ).
 
       
loop at lt_c_hist into ls_c_hist.
 
         
create data lr_table_line.
 
         
create object lr_valuenode
           
exporting
              iv_data_ref
= lr_table_line.
 
          lr_valuenode
->set_properties( ls_c_hist ).
          lr_wrapper
->add( lr_valuenode ).
       
endloop.
     
endif.

In my sample I selected two most expensive assignment blocks: Interaction History and Change History, and executed a data retrieval for them in parallel. 

/wp-content/uploads/2015/12/image024_849965.png

Note that we are not changing the logic of WEBUI framework and therefore all your GET-methods, iterators, events and navigation links will work as usual.

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply