Cutter
Cutter

Reputation: 1820

Why are some RFCs restricted by max. number of GUI sessions?

Calling the function ME_INFORECORD_MAINTAIN_MULTI multiple times via RFC fails with the short dump "Maximum number of GUI sessions reached", but other functions don't seem to be subjected to the sessions limit when called in the same way.

The number of parallel calls to this function that I'm allowed to make depends on the number of GUI sessions (SAP GUI windows) that I have currently opened.

For example, the following code fails after 5 calls (I've added >>> at the beginning of the line where the dump occurs):

FORM CALL_BAPI_INFORECORD.
lv_taskname = |PIR-{ lv_sentjobs WIDTH = 3 ALIGN = RIGHT PAD = '0' }|.
DATA: lv_retry TYPE ABAP_BOOL.
lv_retry = ABAP_TRUE.

WHILE lv_retry = ABAP_TRUE.
  lv_retry = ABAP_FALSE.
  CALL FUNCTION 'ME_INFORECORD_MAINTAIN_MULTI'
    STARTING NEW TASK lv_taskname
    DESTINATION IN GROUP DEFAULT
    PERFORMING RETURN_BAPI_INFORECORD ON END OF TASK
    [...]
  EXCEPTIONS
    system_failure        = 1 MESSAGE lv_exceptionmsg
    communication_failure = 2 MESSAGE lv_exceptionmsg
    resource_failure      = 3
CASE sy-subrc.
  WHEN 0.
    lv_sentjobs = lv_sentjobs + 1.
  WHEN 1 OR 2.
    MESSAGE lv_exceptionmsg TYPE 'I'.
    WRITE: / lv_taskname, ':', lv_exceptionmsg.
  WHEN 3.
    WAIT FOR ASYNCHRONOUS TASKS UNTIL lv_recvjobs = lv_sentjobs UP TO 300 SECONDS.
    lv_retry = ABAP_TRUE.
  WHEN OTHERS.
    MESSAGE 'Unkown error.' TYPE 'I'.
ENDCASE.
ENDWHILE.
ENDFORM.

FORM RETURN_BAPI_INFORECORD USING TASKNAME.
  DATA INFO LIKE RFCSI.
>>> RECEIVE RESULTS FROM FUNCTION 'ME_INFORECORD_MAINTAIN_MULTI'
    IMPORTING
      RFCSI_EXPORT = INFO
      RETURN = GT_ME_INFORECORD_RETURN.
ENDFORM.

... but the following code runs fine with 10 parallel calls:

FORM CALL_BAPI_MATERIAL.
lv_taskname = |MAT-{ lv_sentjobs WIDTH = 3 ALIGN = RIGHT PAD = '0' }|.
DATA: lv_retry TYPE ABAP_BOOL.
lv_retry = ABAP_TRUE.

WHILE lv_retry = ABAP_TRUE.
lv_retry = ABAP_FALSE.
  CALL FUNCTION 'BAPI_MATERIAL_SAVEREPLICA'
    STARTING NEW TASK lv_taskname
    DESTINATION IN GROUP DEFAULT
    PERFORMING RETURN_BAPI_MATERIAL ON END OF TASK
    [...]
  EXCEPTIONS
    system_failure        = 1 MESSAGE lv_exceptionmsg
    communication_failure = 2 MESSAGE lv_exceptionmsg
    resource_failure      = 3.

CASE sy-subrc.
  WHEN 0.
    lv_sentjobs = lv_sentjobs + 1.
  WHEN 1 OR 2.
    MESSAGE lv_exceptionmsg TYPE 'I'.
    WRITE: / lv_taskname, ':', lv_exceptionmsg.
  WHEN 3.
    WAIT FOR ASYNCHRONOUS TASKS UNTIL lv_recvjobs = lv_sentjobs UP TO 300 SECONDS.
    lv_retry = ABAP_TRUE.
  WHEN OTHERS.
    MESSAGE 'Unknown error.' TYPE 'I'.
ENDCASE.
ENDWHILE.
ENDFORM.

FORM RETURN_BAPI_MATERIAL USING TASKNAME.
  DATA INFO LIKE RFCSI.
  RECEIVE RESULTS FROM FUNCTION 'BAPI_MATERIAL_SAVEREPLICA'
    IMPORTING
      RFCSI_EXPORT = INFO
      RETURNMESSAGES = GT_BAPI_SAVEREPLICA_RETURN.
ENDFORM.

This is the stack when the dump occurs.

enter image description here

Why is function ME_INFORECORD_MAINTAIN_MULTI subject to a limit of GUI sessions and how to bypass it ?

Upvotes: 2

Views: 1639

Answers (2)

Wilbert Sison
Wilbert Sison

Reputation: 1

There are some cases where function modules raises GUI sessions ("ABAP sessions") internally. It's caused by internal processing that calls dialog modules.

"When dynpros are called in aRFC processing, additional ABAP sessions are opened in the RFC client (see also RFC Dialog Interactions. The maximum number of ABAP sessions cannot be exceeded and if there are more, an error message is displayed. The maximum number of sessions is defined in the profile parameter rdisp/max_alt_modes and cannot be greater than 16."

https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abapcall_function_starting.htm

Upvotes: 0

phil soady
phil soady

Reputation: 11348

Are you sure you got error

"Maximum number of GUI sessions reached"

due to the function call?

CALL FUNCTION 'BAPI_MATERIAL_SAVEREPLICA'
    STARTING NEW TASK lv_taskname
    DESTINATION IN GROUP DEFAULT
    PERFORMING RETURN_BAPI_MATERIAL ON END OF TASK

Did you include the exceptions on the call function statement?

    exceptions   resource_failure =  1
                 others         = 2.

When there are no more free resources on the Group you will get a 'resource_failure' exception. I would expect a resource failure error based on your description.

Check the settings in Rz12 of for the server group you are using. The ability to "start new task" (via rfc) checks these parameter settings. So if the server was "busy" then the call fails. enter image description here

Here is a basic shell program you can use to test parallel code behavior.

REPORT ZPARA.
data t type i.

parameters:
            cnt    type i default 10000000,
            packets type i default 10,
            para as checkbox default 'X',
            waittime type i default 1,
            rfcgroup like rzllitab-classname .


data  total type f.
data  splits type i.
data  mod type i.
data packetsize type i.
data: first type i.
data: last type i.
data: this_last type i.
data: this_split type i.
data: ret_splits type i.
data: act_splits type i.
data: taskname type num8 value 0.
data: begin of task occurs 0,
     taskname type num8,
     uzeit like sy-uzeit,
     wpinfo TYPE WPINFO,
     end of task.

data max_pbt_wps type i.
data free_pbt_wps type i.
 
start-of-selection.

    PERFORM classic_version.


form classic_version.
**** TO USE THIS CODE,
* create a parallel(rfc) server group in RZ12.
* create the function decribed below 
**************************************************
* set run time res low, so measurement in milli not microsecs.
* we are measure BIG runs

refresh task.

set run time clock resolution low.
get run time field t.
total = 0.

check cnt > 0.

if packets = 0.
   packets = 5.
endif.

* splits calculated based on packet size

splits = packets.
PACKETSIZE = cnt div PACKETS.

* is parallel mode selected
if para = 'X'.

* parallel processing MUST be initialized first.

  call function 'SPBT_INITIALIZE'
   exporting
      group_name                           = rfcgroup
    importing
      max_pbt_wps                          = max_pbt_wps
      free_pbt_wps                         = free_pbt_wps
    exceptions
      invalid_group_name                   = 1
      internal_error                       = 2
      pbt_env_already_initialized          = 3
      currently_no_resources_avail         = 4
      no_pbt_resources_found               = 5
      cant_init_different_pbt_groups       = 6
      others                               = 7
            .
  if sy-subrc <> 0.
* if our group failed or the available processes was 0,
* we would exit cleanly here.
* for the demo, just bomb out.

  endif.


   last = 0.
   ret_splits = 0.
  act_splits = 0.

* so for each split
  do splits times.

* make a jobname
    taskname    = taskname + 1.

* work out which chunk we are processing
* ie were are we up to ??
    first       = last + 1.
    this_last   = first + packetsize - 1.

* for info purposes record which split
    this_split = sy-index.

* just in case we have the last split,
* calculated adjust target end,
    if this_last > cnt.
      this_last = cnt.
    endif.

* try a dispatch this split.
* this is where more logic is needed.
* here we set a max of a hundred tries to dispatch
* something. IN VERY LARGE jobs,
* a commit work and a more intelligent wait
* might be appropriate.
* we at least wait, 1 then 2 then 3... secs etc
* until we get a look in.
   do 100 times.


* inside a parallel ( new ) task
* do a chunk of work.
* NO importing parameters here. The result is returned
* in the receiving function.
* SPECIAL, extra, exceptions are available to control
* success or otherwise of the dispatch.
    write: / 'Split ', this_split, 'dispatch at', sy-uzeit.

    call function 'Z_CHUNK' starting new task taskname
        destination in group rfcgroup
        performing finished on end of task
       exporting

        from_int       = first
        to_int         = this_last

      exceptions
        resource_failure =  1
        others         = 2.

     if sy-subrc = 0.
*    dispatch ok, record the fact and march on...
        act_splits = act_splits + 1.
        last =  first + PACKETSIZE - 1.
        exit. " the retry until dispatched loop.
     else.
      write: 'No resource free'.
      write: / 'Split ', this_split, 'Waits ', waittime, 'secs at',
      sy-uzeit.
* wait x seconds, each attempt waits successlively longer
      wait up to waittime seconds.

     endif.

   enddo.

* Actual failure to dispatch is not captured in this version
* your code should consider this issue.

  enddo.

*** THE BIG ROUNDUP
* we wait here until ALL splits are returned.
* we do that by waiting until a return counter
* equals the numbers of dispatches.
* this wait does not wait indefinitely if a dispatch above
* fails, since another continue point is NO oustanding
* async tasks.
***
  wait until ret_splits >= act_splits.

else.

  call function 'Z_CHUNK'
       exporting
            from_int = 1
            to_int   = cnt
       importing
            tot      = total.




endif.

get run time field t.
t = t / 1000.
loop at task.

  write: / 'Received task', task-taskname, ' at ', task-uzeit, ' in WP:', task-WPINFO-WP_INDEX.

endloop.

write: / 'Parallel', para.
write: / 'Time ms ', t left-justified.
write: / 'Splits  ', splits left-justified.
write: / 'Total   ', total left-justified.

endform.

*---------------------------------------------------------------------*
*       FORM finished                                                 *
*---------------------------------------------------------------------*
*       ........                                                      *
*---------------------------------------------------------------------*
*  -->  TASKNAME                                                      *
*---------------------------------------------------------------------*
form finished using taskname.
data: ls_wpinfo type WPINFO.
data  l_tot type f.


  receive results from function 'Z_CHUNK'
     importing
        tot = l_tot
        wp_index = LS_WPINFO-WP_INDEX.

* when receiving a task back, we get out result
* and record that the task returned, by uping a counter.



  task-taskname =  taskname.
  task-uzeit = sy-uzeit.
  task-WPINFO = LS_WPINFO.
  append task.

  total = total + l_tot.

  ret_splits = ret_splits + 1.

endform.



*****
* Create this function to test.
FUNCTION Z_CHUNK
  IMPORTING
    VALUE(FROM_INT) TYPE I
    VALUE(TO_INT) TYPE I
  EXPORTING
    VALUE(TOT) TYPE F
    VALUE(WP_INDEX) TYPE WPINFO-WP_INDEX.




data l_i type i.

tot = 0.

check to_int > from_int.

l_i = from_int.

while l_i <= to_int.
   tot = tot + l_i.
   l_i = l_i + 1.
endwhile.

CALL FUNCTION 'TH_GET_OWN_WP_NO'
 IMPORTING
   WP_INDEX       = WP_INDEX
          .

ENDFUNCTION.

Upvotes: -1

Related Questions